/** * Type definitions for the Majk Interface * These types define what's available to plugins via ctx.majk * * Extracted from majk app interface definitions without implementation dependencies */ export type EntityId = string; export type Unsubscribe = () => void; export interface BaseEntity { id: EntityId; createdAt: Date; updatedAt: Date; version: number; } export type StandardEventType = 'created' | 'updated' | 'deleted'; export type PluginEventType = 'installing' | 'installed' | 'install_failed' | 'starting' | 'started' | 'start_failed' | 'stopping' | 'stopped' | 'stop_failed' | 'uninstalling' | 'uninstalled' | 'uninstall_failed' | 'reloading' | 'reloaded' | 'reload_failed' | 'enabling' | 'enabled' | 'disabling' | 'disabled'; export type RepositoryEventType = StandardEventType | PluginEventType; export type EntityType = 'message' | 'conversation' | 'agent' | 'tool' | 'project' | 'mcpServer' | 'event' | 'execution' | 'toolGeneration' | 'archivedConversation' | 'teamMember' | 'prompt' | 'workflow' | 'integration' | 'credential' | 'variable' | 'file' | 'workspace' | 'task' | 'notebook' | 'collection' | 'todo' | 'setting' | 'template' | 'snippet' | string; export interface RepositoryEvent { type: RepositoryEventType; entityType: EntityType; entity: T; timestamp: Date; metadata?: { source?: string; operationId?: string; userId?: string; conversationId?: string; [key: string]: any; }; } export interface EventFilter { entityType?: EntityType | EntityType[]; eventType?: RepositoryEventType | RepositoryEventType[]; entityId?: EntityId | EntityId[]; predicate?: (event: RepositoryEvent) => boolean; metadata?: { [key: string]: any; }; } export type EventListener = (event: RepositoryEvent) => void | Promise; export interface Subscription { unsubscribe: () => void; id: string; filter?: EventFilter | 'ALL_EVENTS'; } export interface QueryBuilder { whereType(eventType: RepositoryEventType): QueryBuilder; where(predicate: (event: RepositoryEvent) => boolean): QueryBuilder; subscribe(listener: EventListener): Promise; } export interface QueryableEventChannel { query(): QueryBuilder; onCreated(listener: (entity: T) => void | Promise): Promise; onUpdated(listener: (entity: T) => void | Promise): Promise; onDeleted(listener: (entity: T) => void | Promise): Promise; subscribe(listener: EventListener, filter?: EventFilter): Promise; } export interface EventBusAPI { messages(): QueryableEventChannel; conversations(): QueryableEventChannel; agents(): QueryableEventChannel; tools(): QueryableEventChannel; projects(): QueryableEventChannel; mcpServers(): QueryableEventChannel; integrations(): QueryableEventChannel; todos(): QueryableEventChannel; channel(entityType: string): QueryableEventChannel; subscribe(listener: EventListener, filter?: EventFilter): Promise; subscribeAll(listener: (event: RepositoryEvent) => void): Promise; getDiagnostics(): { channels: string[]; stats: { eventsEmitted: Record; listenersRegistered: Record; }; listeners: Array<{ entityType: string; count: number; }>; lastEventTime?: Date; }; } export interface PluginInfo { id: string; name: string; version: string; description?: string; author?: string; type: 'in-process' | 'external-process'; enabled: boolean; running: boolean; root: string; health?: PluginHealth; hotReloadEnabled?: boolean; } export interface PluginHealth { healthy: boolean; errors?: string[]; warnings?: string[]; lastChecked?: Date; } export interface PluginCapabilityInfo { type: string; data: any; } export interface PluginLog { timestamp: Date; level: 'debug' | 'info' | 'warn' | 'error' | 'system' | 'stdout' | 'stderr'; message: string; args?: any[]; } export interface RegistryConfig { registry: string; token?: string; alwaysAuth?: boolean; } export interface InstallPluginOptions { ignoreScripts?: boolean; enableOnInstall?: boolean; startOnInstall?: boolean; registry?: RegistryConfig; } export interface InstallPluginResult { pluginId: string; version: string; root: string; } export interface GetLogsOptions { level?: 'debug' | 'info' | 'warn' | 'error' | 'system' | 'stdout' | 'stderr'; since?: Date; limit?: number; } export interface GetPluginExternalUrlOptions { theme?: string; path?: string; hash?: string; queryParams?: Record; } export interface GetPluginScreenUrlOptions { screenId?: string; theme?: string; hash?: string; queryParams?: Record; } export interface PluginManagementAPI { install(identifier: string, options?: InstallPluginOptions): Promise; uninstall(pluginId: string): Promise; list(): Promise; get(pluginId: string): Promise; start(pluginId: string): Promise; stop(pluginId: string): Promise; restart(pluginId: string): Promise; reload(pluginId: string): Promise; enable(pluginId: string): Promise; disable(pluginId: string): Promise; isRunning(pluginId: string): boolean; getHealth(pluginId: string): Promise; getCapabilities(pluginId: string): Promise; getLogs(pluginId: string, options?: GetLogsOptions): Promise; clearLogs(pluginId: string): Promise; setHotReload(pluginId: string, enabled: boolean): Promise; isHotReloadEnabled(pluginId: string): Promise; getPluginExternalUrl(pluginId: string, options?: GetPluginExternalUrlOptions): Promise; getPluginScreenUrl(pluginId: string, options?: GetPluginScreenUrlOptions): Promise; getExternalUrl(pluginId: string, pluginPath?: string, pluginPathHash?: string): Promise; } export interface SecretScope { type: 'global' | 'project' | 'integration'; id?: string; } export interface SecretInfo { key: string; scope: SecretScope; description?: string; createdAt: Date; updatedAt: Date; lastUsedAt?: Date; tags?: string[]; } export interface ScopedSecretsAPI { set(key: string, value: string): Promise; get(key: string): Promise; has(key: string): Promise; list(): Promise; delete(key: string): Promise; } export interface SecretsAPI { set(key: string, value: string, scope?: SecretScope): Promise; get(key: string, scope?: SecretScope): Promise; has(key: string, scope?: SecretScope): Promise; list(scope?: SecretScope): Promise; delete(key: string, scope?: SecretScope): Promise; forProject(projectId: string): ScopedSecretsAPI; forIntegration(integrationId: string): ScopedSecretsAPI; } export interface StartTaskRequest { title: string; message: string; agentId?: string; teamMemberId?: string; workingDirectory?: string; context?: Record; triggerImmediately?: boolean; taskType?: 'code-project' | 'automation' | 'analysis' | 'chat' | 'research'; } export interface TaskFilter { status?: 'pending' | 'running' | 'completed' | 'failed'; agentId?: string; teamMemberId?: string; startedAfter?: Date; startedBefore?: Date; } export interface TaskMessage { role: 'user' | 'assistant' | 'tool' | 'system'; content: string; timestamp: Date; seq: number; } export interface TaskProgress { stage?: string; message?: string; percentage?: number; messageCount?: number; toolCall?: { name: string; status: string; }; } export interface TaskResult { success: boolean; output?: any; error?: string; conversationId?: string; duration?: number; } export interface TaskError { code: string; message: string; details?: any; } export interface TaskHandle { readonly id: string; readonly conversationId: string; readonly title: string; /** * @deprecated Returns stale snapshot from construction time. Use getStatus() instead. */ readonly status: 'pending' | 'running' | 'completed' | 'failed'; readonly agentId: string; readonly teamMemberId?: string; readonly startedAt: Date; readonly completedAt?: Date; send(message: string): Promise; sendFollowup(message: string): Promise; waitForCompletion(timeout?: number): Promise; stop(): Promise; getStatus(): Promise<'pending' | 'running' | 'completed' | 'failed'>; isComplete(): Promise; onMessage(handler: (message: TaskMessage) => void): Promise; onProgress(handler: (progress: TaskProgress) => void): Promise; onComplete(handler: (result: TaskResult) => void): Promise; onError(handler: (error: TaskError) => void): Promise; getMessages(): Promise; getConversation(): Promise; } export type TaskEventHandler = (event: TaskEvent) => void; export interface TaskEvent { taskId: string; conversationId: string; agentId: string; timestamp: Date; } export interface TaskAPI { start(request: StartTaskRequest): Promise; get(taskId: string): Promise; list(filter?: TaskFilter): Promise; onTaskStarted(handler: TaskEventHandler): Promise; onTaskCompleted(handler: TaskEventHandler): Promise; onTaskFailed(handler: TaskEventHandler): Promise; } export type AccountType = 'aws-cognito' | 'azure-entra' | 'gcp-iam' | 'api-key' | 'system-default' | string; export interface AccountMetadata { region?: string; createdAt: Date; lastUsedAt?: Date; [key: string]: any; } export interface TimeWindow { milliseconds?: number; seconds?: number; minutes?: number; hours?: number; } export interface CredentialOptions { forceRefresh?: boolean; purpose?: string; timeout?: number; } export interface RefreshOptions { force?: boolean; } export interface RefreshResult { success: boolean; expiresAt?: Date; error?: string; } export interface ValidationResult { valid: boolean; reason?: string; details?: any; } export interface TokenInfo { expiresAt: Date; issuedAt: Date; timeUntilExpiry: number; isExpired: boolean; scopes?: string[]; } export interface AutoRefreshConfig { beforeExpiry: TimeWindow; onRefresh?: (result: RefreshResult) => void; onError?: (error: Error) => void; } export interface AutoRefreshHandle { stop(): void; isActive(): boolean; refresh(): Promise; } export interface AwsSdkCredentials { accessKeyId: string; secretAccessKey: string; sessionToken: string; expiration?: Date; } export interface CognitoTokenSet { idToken: string; accessToken: string; refreshToken: string; expiresAt: Date; } export interface AzureSdkCredentials { accessToken: string; subscriptionId: string; tenantId: string; expiration?: Date; } export interface AccountJSON { id: string; name: string; type: AccountType; expiresAt?: string; metadata: AccountMetadata; } interface BaseCredentials { accountType: AccountType; accountId: string; expiresAt?: Date; metadata: { issuedAt: Date; region?: string; [key: string]: any; }; } export interface AwsCognitoCredentials extends BaseCredentials { accountType: 'aws-cognito'; bearerToken: string; aws: { accessKeyId: string; secretAccessKey: string; sessionToken: string; region: string; }; cognito: { idToken: string; accessToken: string; refreshToken: string; }; } export interface AzureEntraCredentials extends BaseCredentials { accountType: 'azure-entra'; bearerToken: string; azure: { accessToken: string; subscriptionId: string; tenantId: string; region: string; }; } export interface ApiKeyCredentials extends BaseCredentials { accountType: 'api-key'; apiKey: string; baseUrl?: string; } export interface SystemDefaultCredentials extends BaseCredentials { accountType: 'system-default'; } export type Credentials = AwsCognitoCredentials | AzureEntraCredentials | ApiKeyCredentials | SystemDefaultCredentials; export interface SystemAccount { readonly id: string; readonly name: string; readonly type: AccountType; readonly expiresAt?: Date; readonly metadata: AccountMetadata; getCredentials(options?: CredentialOptions): Promise; isValid(): Promise; isExpired(): boolean; isExpiringSoon(window?: TimeWindow): boolean; isOAuthAccount(): this is OAuthAccount; isAwsAccount(): this is AwsAccount; isAzureAccount(): this is AzureAccount; toJSON(): AccountJSON; } export interface OAuthAccount extends SystemAccount { refresh(options?: RefreshOptions): Promise; validate(): Promise; getTokenInfo(): Promise; autoRefresh(config: AutoRefreshConfig): AutoRefreshHandle; } export interface AwsAccount extends OAuthAccount { type: 'aws-cognito'; getRegion(): string; getBedrockToken(): Promise; getAwsCredentials(): Promise; getCognitoTokens(): Promise; } export interface AzureAccount extends OAuthAccount { type: 'azure-entra'; getRegion(): string; getAzureToken(): Promise; getAzureCredentials(): Promise; } export type AuthEvent = AuthStateChangeEvent | AuthTokenRefreshedEvent | AuthErrorEvent | AccountChangedEvent; export interface AuthStateChangeEvent { type: 'auth:state-changed'; isAuthenticated: boolean; accountId?: string; accountType?: AccountType; timestamp: Date; } export interface AuthTokenRefreshedEvent { type: 'auth:token-refreshed'; accountId: string; expiresAt: Date; timestamp: Date; } export interface AuthErrorEvent { type: 'auth:error'; error: string; accountId?: string; timestamp: Date; } export interface AccountChangedEvent { type: 'auth:account-changed'; action: 'added' | 'removed' | 'updated' | 'selected'; accountId: string; accountType: AccountType; timestamp: Date; } export interface AuthAPI { getAccount(): Promise; getAccountsOfType(type: AccountType | '*'): Promise; getCredentials(options?: CredentialOptions): Promise; isAuthenticated(): Promise; } export interface Message extends BaseEntity { conversationId: string; role: 'user' | 'assistant' | 'tool' | 'system'; content: string; seq: number; } export interface Conversation extends BaseEntity { agentId: string; title: string; status: 'active' | 'completed' | 'failed' | 'cancelled'; messageCount: number; lastMessageAt?: Date; workingDirectory?: string; projectId?: string; teamMemberId?: string; startedAt?: Date; endedAt?: Date; completion?: any; metadata?: Record; } export interface Agent extends BaseEntity { name: string; description: string; systemPrompt: string; model: string; temperature?: number; maxTokens?: number; mcpServerIds: string[]; isActive: boolean; tags: string[]; configuration?: { streaming?: boolean; timeout?: number; retryAttempts?: number; rateLimiting?: { requestsPerMinute?: number; tokensPerMinute?: number; }; customHeaders?: Record; }; } export interface TeamMemberSkills { primary: string[]; secondary: string[]; languages: string[]; frameworks: string[]; tools: string[]; } export interface TeamMemberPersonality { workStyle?: string; codeStyle?: string; reviewStyle?: string; communicationStyle?: string; } export interface TeamMemberCodeStats { linesWritten: number; filesModified: number; testsWritten: number; reviewsPassed: number; commitsCreated: number; } export interface TeamMemberMetadata { totalTasks: number; successfulTasks: number; projectHistory: string[]; codeStats: TeamMemberCodeStats; [key: string]: any; } /** * Service function binding for teammates * Defines which plugin functions are available to a teammate */ export interface ServiceFunctionBinding { pluginId: string; serviceName: string; functionName: string; identityBindings: Record; } export interface TeamMember extends BaseEntity { name: string; role: string; skills: TeamMemberSkills; systemPrompt?: string; model?: string; mcpServerIds: string[]; projectIds: string[]; isActive: boolean; personality: TeamMemberPersonality; expertise: string[]; metadata: TeamMemberMetadata; avatar?: string; title?: string; tags?: string[]; /** * Service functions available to this teammate * Populated from plugin's functions field at build time * Always includes identityBindings (empty object if none specified) */ selectedServiceFunctions?: ServiceFunctionBinding[]; } export interface Todo extends BaseEntity { title: string; description?: string; status: 'pending' | 'active' | 'completed'; priority: 'low' | 'medium' | 'high'; assignedTo?: string; projectId?: string; conversationIds: string[]; metadata?: Record; } export type WorkStrategy = 'autonomous' | 'collaborative' | 'supervised' | 'manual' | string; export interface Project extends BaseEntity { name: string; description?: string; path: string; workStrategy: WorkStrategy; teamMemberIds: string[]; } export interface MCPServer extends BaseEntity { name: string; description?: string; type: 'local' | 'remote' | 'docker'; status: string; connectionConfig: any; toolIds: string[]; } export interface ConversationFilter { status?: 'active' | 'completed' | 'failed' | 'cancelled'; agentId?: string; projectId?: string; teamMemberId?: string; createdAfter?: Date; createdBefore?: Date; } export interface MessageQueryOptions { limit?: number; beforeSeq?: number; afterSeq?: number; } export interface ConversationHandle { readonly id: string; readonly agentId: string; readonly title: string; readonly status: 'active' | 'completed' | 'failed' | 'cancelled'; readonly messageCount: number; readonly lastMessageAt?: Date; readonly workingDirectory?: string; readonly projectId?: string; readonly teamMemberId?: string; readonly createdAt: Date; readonly updatedAt: Date; readonly version: number; refresh(): Promise; getMessages(options?: MessageQueryOptions): Promise; send(message: string): Promise; getAgent(): Promise; onChange(handler: (entity: Conversation) => void): Unsubscribe; onDelete(handler: () => void): Unsubscribe; toEntity(): Conversation; } export interface ConversationAPI { get(id: string): Promise; list(filter?: ConversationFilter): Promise; exists(id: string): Promise; count(filter?: ConversationFilter): Promise; search(query: string): Promise; channel(): any; } export interface CreateTeammateRequest { name: string; role: string; skills?: TeamMemberSkills; systemPrompt?: string; model?: string; mcpServerIds?: string[]; personality?: TeamMemberPersonality; expertise?: string[]; metadata?: Partial; avatar?: string; title?: string; tags?: string[]; } export interface TeammateUpdate { name?: string; role?: string; skills?: TeamMemberSkills; systemPrompt?: string; model?: string; mcpServerIds?: string[]; isActive?: boolean; personality?: TeamMemberPersonality; expertise?: string[]; metadata?: Partial; avatar?: string; title?: string; tags?: string[]; } export interface TeammateFilter { role?: string; isActive?: boolean; projectId?: string; } export interface TeammateHandle { readonly id: string; readonly name: string; readonly role: string; readonly skills: TeamMemberSkills; readonly systemPrompt?: string; readonly model?: string; readonly mcpServerIds: string[]; readonly projectIds: string[]; readonly isActive: boolean; readonly personality: TeamMemberPersonality; readonly expertise: string[]; readonly metadata: TeamMemberMetadata; readonly avatar?: string; readonly title?: string; readonly tags?: string[]; readonly createdAt: Date; readonly updatedAt: Date; readonly version: number; refresh(): Promise; update(updates: Partial): Promise; delete(): Promise; assignToProject(projectId: string): Promise; unassignFromProject(projectId: string): Promise; getProjects(): Promise; onChange(handler: (entity: TeamMember) => void): Unsubscribe; onDelete(handler: () => void): Unsubscribe; toEntity(): TeamMember; } export interface TeammateAPI { create(data: CreateTeammateRequest): Promise; get(id: string): Promise; list(filter?: TeammateFilter): Promise; update(id: string, updates: TeammateUpdate): Promise; delete(id: string): Promise; exists(id: string): Promise; count(filter?: TeammateFilter): Promise; channel(): any; } export interface CreateTodoRequest { title: string; description?: string; status?: 'pending' | 'active' | 'completed'; priority?: 'low' | 'medium' | 'high'; assignedTo?: string; projectId?: string; metadata?: Record; } export interface TodoUpdate { title?: string; description?: string; status?: 'pending' | 'active' | 'completed'; priority?: 'low' | 'medium' | 'high'; assignedTo?: string; projectId?: string; metadata?: Record; } export interface TodoFilter { status?: 'pending' | 'active' | 'completed'; priority?: 'low' | 'medium' | 'high'; assignedTo?: string; projectId?: string; } export interface SpawnOptions { message?: string; agentId?: string; triggerImmediately?: boolean; } export interface TodoHandle { readonly id: string; readonly title: string; readonly description?: string; readonly status: 'pending' | 'active' | 'completed'; readonly priority: 'low' | 'medium' | 'high'; readonly assignedTo?: string; readonly projectId?: string; readonly conversationIds: string[]; readonly metadata?: Record; readonly createdAt: Date; readonly updatedAt: Date; readonly version: number; refresh(): Promise; update(updates: Partial): Promise; delete(): Promise; complete(): Promise; assignTo(teammateId: string): Promise; linkToConversation(conversationId: string): Promise; spawn(options?: SpawnOptions): Promise; onChange(handler: (entity: Todo) => void): Unsubscribe; onDelete(handler: () => void): Unsubscribe; toEntity(): Todo; } export interface TodoAPI { create(data: CreateTodoRequest): Promise; get(id: string): Promise; list(filter?: TodoFilter): Promise; update(id: string, updates: TodoUpdate): Promise; delete(id: string): Promise; exists(id: string): Promise; count(filter?: TodoFilter): Promise; channel(): any; } export interface CreateProjectRequest { name: string; description?: string; path: string; workStrategy?: WorkStrategy; teamMemberIds?: string[]; } export interface ProjectUpdate { name?: string; description?: string; path?: string; workStrategy?: WorkStrategy; teamMemberIds?: string[]; } export interface ProjectFilter { teamMemberId?: string; } export interface ProjectHandle { readonly id: string; readonly name: string; readonly description?: string; readonly path: string; readonly workStrategy: WorkStrategy; readonly teamMemberIds: string[]; readonly createdAt: Date; readonly updatedAt: Date; readonly version: number; refresh(): Promise; update(updates: Partial): Promise; delete(): Promise; addTeammate(teammateId: string): Promise; removeTeammate(teammateId: string): Promise; getTeammates(): Promise; setWorkStrategy(strategy: WorkStrategy): Promise; onChange(handler: (entity: Project) => void): Unsubscribe; onDelete(handler: () => void): Unsubscribe; toEntity(): Project; } export interface ProjectAPI { create(data: CreateProjectRequest): Promise; get(id: string): Promise; list(filter?: ProjectFilter): Promise; update(id: string, updates: ProjectUpdate): Promise; delete(id: string): Promise; exists(id: string): Promise; count(filter?: ProjectFilter): Promise; channel(): any; } export interface CreateMCPServerRequest { name: string; description?: string; type: 'local' | 'remote' | 'docker'; connectionConfig: { command?: string; args?: string[]; env?: Record; workingDirectory?: string; url?: string; }; } export interface MCPServerUpdate { name?: string; description?: string; connectionConfig?: { command?: string; args?: string[]; env?: Record; workingDirectory?: string; url?: string; }; } export interface MCPServerFilter { type?: 'local' | 'remote' | 'docker'; status?: 'connected' | 'disconnected' | 'error'; } export interface ConnectionTestResult { success: boolean; error?: string; latency?: number; } export interface MCPServerHandle { readonly id: string; readonly name: string; readonly description?: string; readonly type: 'local' | 'remote' | 'docker'; readonly status: string; readonly connectionConfig: any; readonly toolIds: string[]; readonly createdAt: Date; readonly updatedAt: Date; readonly version: number; refresh(): Promise; update(updates: Partial): Promise; delete(): Promise; connect(): Promise; disconnect(): Promise; testConnection(): Promise; getTools(): Promise; onChange(handler: (entity: MCPServer) => void): Unsubscribe; onDelete(handler: () => void): Unsubscribe; toEntity(): MCPServer; asAdmin(): MCPServerScopedHandle; asTeammate(teammateId: string): MCPServerScopedHandle; } export interface MCPServerScopedHandle { discoverTools(): Promise; executeTool(toolName: string, params: Record): Promise; listResources(): Promise; listPrompts(): Promise; getServerInfo(): { id: string; name: string; type: string; context: string; }; connect(): Promise; disconnect(): Promise; } export interface DiscoveredTool { id: string; name: string; description: string; inputSchema?: any; serverId: string; serverName: string; } export interface MCPServerAPI { create(data: CreateMCPServerRequest): Promise; get(id: string): Promise; list(filter?: MCPServerFilter): Promise; update(id: string, updates: MCPServerUpdate): Promise; delete(id: string): Promise; exists(id: string): Promise; count(filter?: MCPServerFilter): Promise; channel(): any; everywhere(): EverywhereScope; } export interface EverywhereScope { asAdmin(): EverywhereScopedHandle; asTeammate(teammateId: string): EverywhereScopedHandle; } export interface EverywhereScopedHandle { discoverTools(): Promise; executeTool(toolName: string, params: Record): Promise; listKnownTools(): Promise; getContextInfo(): { type: string; id?: string; metadata: Record; }; } export interface CreateAgentRequest { name: string; description?: string; systemPrompt: string; model: string; temperature?: number; maxTokens?: number; mcpServerIds?: string[]; configuration?: { streaming?: boolean; timeout?: number; retryAttempts?: number; rateLimiting?: { requestsPerMinute?: number; tokensPerMinute?: number; }; customHeaders?: Record; }; tags?: string[]; isActive?: boolean; } export interface AgentUpdate { name?: string; description?: string; systemPrompt?: string; model?: string; temperature?: number; maxTokens?: number; mcpServerIds?: string[]; configuration?: { streaming?: boolean; timeout?: number; retryAttempts?: number; rateLimiting?: { requestsPerMinute?: number; tokensPerMinute?: number; }; customHeaders?: Record; }; tags?: string[]; isActive?: boolean; } export interface AgentFilter { isActive?: boolean; model?: string; tags?: string[]; } export interface TestResult { success: boolean; response?: string; error?: string; duration?: number; } export interface AgentHandle { readonly id: string; readonly name: string; readonly description: string; readonly systemPrompt: string; readonly model: string; readonly temperature?: number; readonly maxTokens?: number; readonly mcpServerIds: string[]; readonly isActive: boolean; readonly tags: string[]; readonly createdAt: Date; readonly updatedAt: Date; readonly version: number; refresh(): Promise; update(updates: Partial): Promise; delete(): Promise; test(message: string): Promise; clone(modifications?: Partial): Promise; getMCPServers(): Promise; addMCPServer(serverId: string): Promise; removeMCPServer(serverId: string): Promise; onChange(handler: (entity: Agent) => void): Unsubscribe; onDelete(handler: () => void): Unsubscribe; toEntity(): Agent; } export interface AgentAPI { create(data: CreateAgentRequest): Promise; get(id: string): Promise; list(filter?: AgentFilter): Promise; update(id: string, updates: AgentUpdate): Promise; delete(id: string): Promise; exists(id: string): Promise; count(filter?: AgentFilter): Promise; test(agentId: string, message: string): Promise; clone(agentId: string, modifications?: Partial): Promise; channel(): any; } export interface AddKnowledgeInput { conversationId: string; title: string; content: string; references?: string[]; tree?: string; } export interface KnowledgeNode { id: string; title: string; content: string; references: string[]; conversationId: string; tree: string; createdAt: Date; } export interface KnowledgeTree { name: string; conversationId: string; nodes: KnowledgeNode[]; } export interface KnowledgeSearchOptions { conversationId?: string; tree?: string; limit?: number; } /** * System-reserved prefixes that plugins cannot use for contributions. */ export declare const RESERVED_PREFIXES: readonly ["/projects", "/teammates", "/tools", "/skills", "/reports", "/characterizations"]; /** * Node status in the Knowledge Fabric. */ export type FabricNodeStatus = 'active' | 'pending' | 'inactive'; /** * A node in the Knowledge Fabric. * * This is the API-facing representation of a fabric node. */ export interface KnowledgeFabricNode { /** Hierarchical key path (e.g., "/plugins/my-plugin/entities/item-1") */ key: string; /** Human-readable title */ title: string; /** The searchable content */ content: string; /** Child node keys */ children: string[]; /** Metadata and source references */ refs: Record; /** Who contributed this node */ contributorId: string; /** Current lifecycle status */ status: FabricNodeStatus; /** When this node was created (timestamp) */ createdAt: number; /** When this node was last contributed (timestamp) */ lastContributed: number; } /** * Input for contributing a node to the fabric. */ export interface ContributeNodeInput { /** * Key for this node (relative to the contribution prefix). * * Will be combined with the contribution prefix: * prefix: "/plugins/my-plugin/entities" * key: "item-1" * → full key: "/plugins/my-plugin/entities/item-1" */ key: string; /** Human-readable title */ title: string; /** Searchable content (what gets embedded for semantic search) */ content: string; /** Optional child keys (relative to prefix) */ children?: string[]; /** Optional metadata/references */ refs?: Record; } /** * Options for semantic search. */ export interface FabricSearchOptions { /** * Scope search to this key prefix. * * @example * // Search only within your plugin's knowledge * { under: handle.prefix } * * // Search within a specific project * { under: '/projects/project-abc123' } */ under?: string; /** Maximum number of results (default: 10, max: 100) */ limit?: number; /** Minimum similarity score 0-1 */ minScore?: number; } /** * A single search result. */ export interface FabricSearchResult { /** The matching node */ node: KnowledgeFabricNode; /** Similarity score 0-1 (1 = most similar) */ score: number; } /** * Response from a search operation. */ export interface FabricSearchResponse { /** Search results ordered by relevance */ results: FabricSearchResult[]; /** Current indexing status */ indexingStatus: { /** Are all nodes in scope fully indexed? */ complete: boolean; /** Number of nodes still being indexed */ pendingCount: number; }; } /** * Result of expanding a node to see its children. */ export interface FabricExpandResult { /** The expanded node */ node: KnowledgeFabricNode; /** Direct children of this node */ children: KnowledgeFabricNode[]; } /** * Overall status of the Knowledge Fabric. */ export interface FabricStatus { /** Total number of nodes in the fabric */ totalNodes: number; /** Number of active, searchable nodes */ activeNodes: number; /** Number of nodes awaiting embedding */ pendingNodes: number; /** Total number of unique embeddings */ totalEmbeddings: number; /** Whether semantic search is available */ searchAvailable: boolean; } /** * Options for registering a knowledge contribution. */ export interface RegisterContributionOptions { /** * Custom prefix for this contribution. * * DEFAULT: `/plugins/{pluginId}/{subPrefix}` * * CUSTOM: Any prefix except: * - Reserved system prefixes: /projects, /teammates, /tools, /skills, /reports * - Other plugins' namespaces: /plugins/{otherPluginId}/... * * Prefixes are EXCLUSIVE - first to register owns it. * To share a namespace with other plugins, use sub-prefixes: * Plugin A: /contacts/hubspot * Plugin B: /contacts/salesforce */ prefix?: string; /** * Initial nodes to contribute on registration. * * These are contributed before the handle is returned, * so they're immediately available for search (after indexing). */ initialNodes?: ContributeNodeInput[]; /** * Optional label resolver for virtual nodes in the hierarchy. * * Called when the fabric needs a human-readable label for a path segment. * * @param key - The full key path * @param segment - The specific segment to label * @param depth - The depth of the segment (1-indexed) * @returns Display label, or null to use default formatting */ resolveLabel?: (key: string, segment: string, depth: number) => string | null; } /** * Handle for managing a knowledge contribution. * * Returned by `registerContribution()`. Use this to add, update, * and remove nodes from your contribution. */ export interface KnowledgeContributionHandle { /** * The full key prefix for this contribution. * * All nodes you contribute will be under this prefix. */ readonly prefix: string; /** * The contributor ID for this contribution. * * Format: `plugin:{pluginId}:{subPrefix}` */ readonly contributorId: string; /** * Contribute a single node. * * If a node with this key already exists (from this contributor), * it will be updated. The node will be queued for embedding. * * @param node - The node to contribute */ contribute(node: ContributeNodeInput): Promise; /** * Contribute multiple nodes in batch. * * More efficient than calling contribute() multiple times. * * @param nodes - The nodes to contribute */ contributeBatch(nodes: ContributeNodeInput[]): Promise; /** * Remove a node by key. * * The key is relative to the contribution prefix. * * @param key - The key of the node to remove (relative to prefix) * @returns true if the node was found and removed */ remove(key: string): Promise; /** * Get the current number of nodes in this contribution. */ getNodeCount(): Promise; /** * List all keys in this contribution. * * @param options - Optional filtering options * @returns Array of full keys */ listKeys(options?: { status?: 'active' | 'pending' | 'all'; }): Promise; /** * Reconcile this contribution. * * This re-syncs the contribution by: * 1. Marking all existing nodes as inactive * 2. Re-contributing all nodes from the source * 3. Nodes not re-contributed stay inactive (will be GC'd) * * Useful when the underlying data source may have changed. * * @returns Statistics about what changed */ reconcile(): Promise<{ added: number; updated: number; deactivated: number; }>; /** * Unregister this contribution. * * All nodes from this contribution will be marked inactive * and eventually garbage collected. * * After calling this, the handle is no longer usable. */ unregister(): Promise; } /** * Summary of a contribution for listing. */ export interface ContributionSummary { /** The full key prefix */ prefix: string; /** The contributor ID */ contributorId: string; /** Number of active nodes */ nodeCount: number; /** Number of pending nodes */ pendingCount: number; /** Current status */ status: 'ready' | 'indexing' | 'unregistered'; } /** * Events emitted by the fabric that plugins can subscribe to. */ export type FabricNodeEvent = { type: 'indexed'; key: string; } | { type: 'activated'; key: string; } | { type: 'deactivated'; key: string; } | { type: 'reindexed'; key: string; }; /** * Knowledge Fabric API for plugins. * * Provides unified access to the Knowledge Fabric for: * - Semantic search across all knowledge * - Browsing the knowledge hierarchy * - Contributing plugin-specific knowledge * * Access via `ctx.majk.knowledge.fabric` */ export interface KnowledgeFabricAPI { /** * Semantic search across all knowledge in the system. * * Searches: * - Project notes (knowledge trees) * - Teammates * - Tools * - Plugins * - Skills * - Reports * - Plugin-contributed knowledge * * @param query - Natural language search query * @param options - Search options (scope, limit, min score) * @returns Matching nodes ordered by relevance * * @example * // Search all knowledge * const results = await fabric.search('authentication patterns'); * * // Search within a specific scope * const results = await fabric.search('authentication', { * under: '/projects/my-project', * limit: 5, * minScore: 0.3 * }); */ search(query: string, options?: FabricSearchOptions): Promise; /** * Get root nodes of the knowledge hierarchy. * * @returns Top-level nodes (/projects, /plugins, /teammates, etc.) */ getRoots(): Promise; /** * Expand a node to see its children. * * @param key - The node key to expand * @returns The node and its direct children, or null if not found * * @example * const result = await fabric.expand('/plugins'); * console.log(result.children); // All plugin nodes */ expand(key: string): Promise; /** * Get a single node by key. * * @param key - The node key * @returns The node or null if not found */ getNode(key: string): Promise; /** * Get the current status of the Knowledge Fabric. * * @returns Status including node counts and search availability */ getStatus(): Promise; /** * Register a knowledge contribution for this plugin. * * Creates a scoped namespace for the plugin to contribute knowledge. * Returns a handle for managing nodes in the contribution. * * @param subPrefix - Sub-namespace name (e.g., "entities", "docs") * @param options - Configuration including custom prefix and initial nodes * @returns Handle for managing the contribution * * @example * // Using default prefix (recommended) * const handle = await fabric.registerContribution('contacts', { * initialNodes: [ * { key: 'john', title: 'John Doe', content: 'CEO at Acme Corp...' } * ] * }); * // Prefix: /plugins/{pluginId}/contacts * * // Using custom prefix * const handle = await fabric.registerContribution('contacts', { * prefix: '/crm/contacts' * }); * // Prefix: /crm/contacts */ registerContribution(subPrefix: string, options?: RegisterContributionOptions): Promise; /** * List all contributions registered by this plugin. * * @returns Array of contribution summaries */ listContributions(): Promise; /** * Subscribe to node change events. * * Events are filtered to this plugin's contributions by default. * * @param handler - Event handler function * @param options - Optional filter options * @returns Unsubscribe function * * @example * const unsub = fabric.onNodeChange((event) => { * console.log(`Node ${event.key} was ${event.type}`); * }); * * // Later: unsub(); */ onNodeChange(handler: (event: FabricNodeEvent) => void, options?: { allNodes?: boolean; }): () => void; } export interface KnowledgeAPI { /** * Access to the unified Knowledge Fabric. * * Provides semantic search across all knowledge and * the ability to contribute plugin-specific knowledge. * * @example * // Search all knowledge * const results = await ctx.majk.knowledge.fabric.search('authentication'); * * // Contribute knowledge * const handle = await ctx.majk.knowledge.fabric.registerContribution('contacts'); * await handle.contribute({ key: 'c1', title: 'Contact', content: '...' }); */ readonly fabric: KnowledgeFabricAPI; /** @deprecated Use fabric.search() for semantic search */ add(input: AddKnowledgeInput): Promise; /** @deprecated Use fabric.search() for semantic search */ search(query: string, options?: KnowledgeSearchOptions): Promise; /** @deprecated Use fabric for knowledge operations */ getByReference(ref: string): Promise; /** @deprecated Use fabric for knowledge operations */ getTree(conversationId: string, treeName: string): Promise; /** @deprecated Use fabric for knowledge operations */ listTrees(conversationId: string): Promise; } /** * Capabilities that an AI provider may support. * Providers declare which capabilities they implement. */ export interface AIProviderCapabilities { /** Core language model prompting */ llm: boolean; /** Image generation (DALL-E, Stable Diffusion, etc.) */ imageGeneration?: boolean; /** Text embeddings for semantic search */ embeddings?: boolean; /** Audio transcription (Whisper, etc.) */ audioTranscription?: boolean; /** Function/tool calling support */ functionCalling?: boolean; /** Structured JSON output with schema enforcement */ structuredOutput?: boolean; /** Streaming response support */ streaming?: boolean; } /** * Information about an AI model */ export interface ModelInfo { /** Model identifier (e.g., "gpt-4", "claude-3-opus") */ id: string; /** Human-readable name */ name: string; /** Model description */ description?: string; /** Context window size in tokens */ contextWindow?: number; /** Supported capabilities */ capabilities?: Partial; /** Pricing information (optional) */ pricing?: { inputTokens?: number; outputTokens?: number; }; } /** * Message in a conversation with an LLM */ export interface AIMessage { /** Role of the message sender */ role: 'system' | 'user' | 'assistant'; /** Message content (string or structured blocks) */ content: string | ContentBlock[]; /** Optional message name (for function calls) */ name?: string; } /** * Structured content block (images, tool use, etc.) */ export interface ContentBlock { /** Type of content */ type: 'text' | 'image' | 'tool_use' | 'tool_result'; /** Block-specific data */ [key: string]: any; } /** * Parameters for LLM prompting */ export interface PromptParams { /** Conversation messages */ messages: AIMessage[]; /** Sampling temperature (0-1, higher = more random) */ temperature?: number; /** Maximum tokens to generate */ maxTokens?: number; /** Stop sequences */ stopSequences?: string[]; /** Top-p sampling */ topP?: number; /** System prompt override (if not in messages) */ system?: string; /** Provider-specific metadata */ metadata?: Record; } /** * Result from an LLM prompt */ export interface PromptResult { /** Generated text content */ content: string; /** Structured content blocks (if any) */ contentBlocks?: ContentBlock[]; /** Stop reason */ stopReason?: 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use'; /** Token usage information */ usage?: { inputTokens: number; outputTokens: number; totalTokens: number; }; /** Provider-specific metadata */ metadata?: Record; } /** * Streaming chunk from an LLM */ export interface PromptChunk { /** Chunk type */ type: 'content_start' | 'content_delta' | 'content_end' | 'message_start' | 'message_end'; /** Partial content (for delta chunks) */ content?: string; /** Content block (for structured content) */ contentBlock?: ContentBlock; /** Final message (for message_end) */ message?: PromptResult; } /** * Function definition for function calling */ export interface AIFunctionDefinition { /** Function name */ name: string; /** Function description */ description: string; /** Parameter schema (JSON Schema) */ parameters: AIJsonSchema; } /** * JSON Schema for structured output */ export interface AIJsonSchema { type: string; properties?: Record; required?: string[]; [key: string]: any; } /** * Parameters for function calling */ export interface FunctionCallParams extends PromptParams { /** Available functions */ functions: AIFunctionDefinition[]; /** Force a specific function to be called */ functionCall?: 'auto' | 'none' | { name: string; }; } /** * Result from a function call */ export interface FunctionCallResult extends PromptResult { /** Function call details (if model invoked a function) */ functionCall?: { name: string; arguments: Record; }; } /** * Parameters for image generation */ export interface ImageGenerationParams { /** Image generation prompt */ prompt: string; /** Negative prompt (what to avoid) */ negativePrompt?: string; /** Image size */ size?: string; /** Number of images to generate */ n?: number; /** Quality/detail level */ quality?: 'standard' | 'hd'; /** Style preset */ style?: string; /** Provider-specific parameters */ metadata?: Record; } /** * Result from image generation */ export interface ImageResult { /** Generated image URLs or data URLs */ images: string[]; /** Revised prompt (if provider modified it) */ revisedPrompt?: string; /** Generation metadata */ metadata?: Record; } /** * Parameters for audio transcription */ export interface TranscriptionParams { /** Audio data buffer */ audio: Buffer; /** Audio format */ format?: 'mp3' | 'wav' | 'webm' | 'ogg'; /** Language hint (ISO 639-1) */ language?: string; /** Include timestamps */ timestamps?: boolean; } /** * Result from audio transcription */ export interface TranscriptionResult { /** Transcribed text */ text: string; /** Language detected */ language?: string; /** Word-level timestamps (if requested) */ timestamps?: Array<{ word: string; start: number; end: number; }>; /** Confidence score */ confidence?: number; } /** * Core interface for language model operations. * Represents a specific model from a provider. */ export interface LLMInterface { /** Provider identifier */ readonly provider: string; /** Model identifier */ readonly model: string; /** * Send a prompt to the model * @param params - Prompt parameters * @returns Promise resolving to the model's response * @throws AIProviderError if the request fails */ prompt(params: PromptParams): Promise; /** * Send a prompt with streaming response * @param params - Prompt parameters * @returns Async iterator of response chunks * @throws AIProviderError if the request fails */ promptStream(params: PromptParams): AsyncIterableIterator; /** * Prompt for structured JSON output * @param params - Prompt parameters with optional schema * @returns Promise resolving to parsed JSON * @throws AIProviderError if the request fails or JSON is invalid */ promptForJson(params: PromptParams & { schema?: AIJsonSchema; }): Promise; /** * Prompt with function calling * @param params - Prompt parameters with function definitions * @returns Promise resolving to response with optional function call * @throws AIProviderError if the request fails */ functionCall(params: FunctionCallParams): Promise; } /** * Provider health and status information */ export interface ProviderStatus { /** Is the provider available? */ available: boolean; /** Is authentication configured and valid? */ authenticated: boolean; /** Rate limit remaining (if applicable) */ rateLimitRemaining?: number; /** Last error message (if any) */ lastError?: string; /** Last successful request timestamp */ lastSuccess?: Date; /** Provider-specific status info */ metadata?: Record; } /** * Main AI provider interface. * Plugins implement this to provide AI capabilities. */ export interface AIProvider { /** Unique provider identifier (e.g., "openai", "anthropic") */ readonly id: string; /** Human-readable provider name */ readonly name: string; /** Declared capabilities */ readonly capabilities: AIProviderCapabilities; /** * Get an LLM interface for a specific model * @param model - Model identifier (optional, uses provider default if omitted) * @returns LLM interface for prompting * @throws AIProviderError if model is not available */ getLLM(model?: string): LLMInterface; /** * List available models * @returns Promise resolving to array of model information * @throws AIProviderError if listing fails */ listModels(): Promise; /** * Generate an image (if provider supports it) * @param params - Image generation parameters * @returns Promise resolving to generated images * @throws AIProviderError if not supported or generation fails */ generateImage?(params: ImageGenerationParams): Promise; /** * Generate text embeddings (if provider supports it) * @param text - Text to embed * @returns Promise resolving to embedding vector * @throws AIProviderError if not supported or generation fails */ generateEmbedding?(text: string): Promise; /** * Transcribe audio (if provider supports it) * @param params - Transcription parameters * @returns Promise resolving to transcription * @throws AIProviderError if not supported or transcription fails */ transcribeAudio?(params: TranscriptionParams): Promise; } /** * Main AI API exposed via majk.ai * Provides access to registered AI providers and convenience methods. */ export interface AIAPI { /** * Get a specific AI provider by ID * @param providerId - Provider identifier (e.g., "openai", "anthropic") * @returns Provider instance or undefined if not found */ getProvider(providerId: string): AIProvider | undefined; /** * List all registered providers * @returns Array of all available providers */ listProviders(): AIProvider[]; /** * Get the default AI provider * @returns Default provider * @throws AIProviderError if no providers are registered */ getDefaultProvider(): AIProvider; /** * Set the default provider * @param providerId - Provider ID to set as default * @throws AIProviderError if provider not found */ setDefaultProvider(providerId: string): Promise; /** * Get an LLM from the default provider * @param model - Optional model identifier * @returns LLM interface using default provider * @throws AIProviderError if no providers registered */ getLLM(model?: string): LLMInterface; /** * Get the default LLM (default provider, default model) * @returns LLM interface with all defaults * @throws AIProviderError if no providers registered */ getDefaultLLM(): LLMInterface; /** * Get all providers that support a specific capability * @param capability - Capability to filter by * @returns Array of providers supporting the capability */ getProvidersWithCapability(capability: keyof AIProviderCapabilities): AIProvider[]; /** * Get provider status and health information * @param providerId - Provider to check * @returns Promise resolving to status information */ getProviderStatus(providerId: string): Promise; } /** * Standard error class for AI provider operations */ export declare class AIProviderError extends Error { readonly providerId?: string | undefined; readonly code?: string | undefined; readonly statusCode?: number | undefined; readonly cause?: Error | undefined; constructor(message: string, providerId?: string | undefined, code?: string | undefined, statusCode?: number | undefined, cause?: Error | undefined); } /** * ConfigAPI - Unified configuration access for Majk plugins * * Provides path-based access to all Majk configuration including: * - AWS resources (plugin market, telemetry, token usage) * - Authentication settings (Cognito, etc.) * - Bedrock AI models * - Plugin system settings * - Any future configuration additions * * Configuration is organized into namespaces: * - aws.* - AWS resources and services * - auth.* - Authentication configuration * - bedrock.* - Bedrock AI model settings * - litellm.* - LiteLLM proxy configuration * - plugins.* - Plugin system configuration * * @example * // Get plugin market endpoint * const endpoint = ctx.majk.config.get("aws.pluginMarket.apiEndpoint"); * * @example * // With default value * const endpoint = ctx.majk.config.get( * "aws.pluginMarket.apiEndpoint", * "https://fallback.com" * ); * * @example * // Get entire section * const marketConfig = ctx.majk.config.get("aws.pluginMarket"); * // Returns: { apiEndpoint: "...", region: "us-east-1", enabled: true } * * @example * // Check if config exists * if (ctx.majk.config.has("aws.pluginMarket.apiEndpoint")) { * // Plugin market is configured * } * * @example * // Discover available config keys * const awsKeys = ctx.majk.config.keys("aws"); * // Returns: ["pluginMarket", "telemetry", "tokenUsage"] */ export interface ConfigAPI { /** * Get a configuration value by path using dot notation * * Supports nested access with dots (e.g., "aws.pluginMarket.apiEndpoint") * Returns undefined if path doesn't exist, or defaultValue if provided * * Type-safe: You can specify the expected return type with generics * * @param path - Dot-notation path to config value (e.g., "aws.telemetry.region") * @param defaultValue - Optional default value if path doesn't exist * @returns The configuration value or defaultValue or undefined * * @example * // Simple get * const region = ctx.majk.config.get("aws.pluginMarket.region"); * * @example * // With default * const enabled = ctx.majk.config.get("aws.pluginMarket.enabled", true); * * @example * // Get object * const telemetry = ctx.majk.config.get("aws.telemetry"); * * @example * // Type-safe * interface MarketConfig { apiEndpoint: string; region: string; } * const config = ctx.majk.config.get("aws.pluginMarket"); */ get(path: string, defaultValue?: T): T | undefined; /** * Check if a configuration path exists * * Returns true if the path exists in the configuration, false otherwise * Useful for feature detection or conditional logic * * @param path - Dot-notation path to check (e.g., "aws.pluginMarket") * @returns True if path exists, false otherwise * * @example * if (ctx.majk.config.has("aws.pluginMarket.apiEndpoint")) { * // Plugin market is configured, use it * const endpoint = ctx.majk.config.get("aws.pluginMarket.apiEndpoint"); * } else { * // Fallback to alternative approach * } * * @example * // Check for experimental features * if (ctx.majk.config.has("experimental.newFeature")) { * // Enable new feature * } */ has(path: string): boolean; /** * Get all configuration keys under a path * * Returns an array of key names at the specified path level * Useful for discovery, iteration, or building dynamic UIs * * @param path - Optional dot-notation path (omit for top-level keys) * @returns Array of key names, or empty array if path doesn't exist * * @example * // Top-level namespaces * ctx.majk.config.keys() * // Returns: ["aws", "auth", "bedrock", "plugins"] * * @example * // Discover AWS resources * ctx.majk.config.keys("aws") * // Returns: ["pluginMarket", "telemetry", "tokenUsage"] * * @example * // Plugin market properties * ctx.majk.config.keys("aws.pluginMarket") * // Returns: ["apiEndpoint", "region", "enabled"] * * @example * // Build dynamic UI * const awsServices = ctx.majk.config.keys("aws"); * awsServices.forEach(service => { * const config = ctx.majk.config.get(`aws.${service}`); * // Display service configuration * }); */ keys(path?: string): string[]; /** * Get the entire configuration object * * Returns a deep copy of the complete unified configuration * Should be used sparingly - prefer specific get() calls * Primarily for debugging, inspection, or advanced scenarios * * @returns Complete configuration object (deep copy) * * @example * // Debugging * console.log('Full config:', ctx.majk.config.getAll()); * * @example * // Config inspection UI * const allConfig = ctx.majk.config.getAll(); * displayConfigTree(allConfig); */ getAll(): Record; } /** * Context passed to skill setup/teardown functions */ export interface SkillContext { /** ID of the teammate enabling the skill */ teammateId: string; /** ID of the current conversation */ conversationId: string; /** Root directory of the project */ projectRootDir: string; /** Workspace directory for the project */ projectWorkspaceDir: string; } /** * Setup function signature - called when skill is enabled * Returns additional context/instructions to prepend to skill instructions */ export type SkillSetupFn = (context: SkillContext) => Promise; /** * Teardown function signature - called when skill is disabled */ export type SkillTeardownFn = (context: SkillContext) => Promise; /** * Base skill definition - shared between DB and runtime skills */ export interface SkillDefinition { /** Unique identifier for the skill */ id: string; /** Display name for the skill */ name: string; /** One-sentence description of what the skill does */ description: string; /** Full instructions on how to accomplish tasks using this skill's tools */ instructions: string; /** Optional tags for categorization and search */ tags?: string[]; /** Optional list of tool names this skill uses */ tools?: string[]; /** Whether the skill is currently enabled */ enabled: boolean; } /** * Runtime-registered skill (can have functions) * Functions are not serialized - they exist only in memory */ export interface RuntimeSkill extends SkillDefinition { /** * Optional setup function - called when skill is enabled. * Can return additional instructions to prepend to the skill. */ setup?: SkillSetupFn; /** * Optional teardown function - called when skill is disabled. * Not currently used but reserved for future use. */ teardown?: SkillTeardownFn; /** Source of the runtime skill (for debugging) */ source?: string; } /** * Unified skill type returned from list/search operations * Omits functions since they don't serialize */ export interface Skill extends SkillDefinition { /** Whether this skill is from the database (true) or runtime (false) */ persisted: boolean; /** Whether this skill has a setup function */ hasSetup: boolean; /** Whether this skill has a teardown function */ hasTeardown: boolean; /** Source of the skill */ source: 'database' | 'runtime'; } /** * Summary of a skill for listing */ export interface SkillSummary { /** Skill ID */ id: string; /** Display name */ name: string; /** One-sentence description */ description: string; /** Whether enabled */ enabled: boolean; /** Source */ source: 'database' | 'runtime'; /** Tags */ tags?: string[]; } export interface AddSkillInput { /** Unique identifier (auto-generated if not provided) */ id?: string; /** Display name */ name: string; /** One-sentence description */ description: string; /** Full instructions */ instructions: string; /** Optional tags */ tags?: string[]; /** Optional tool names */ tools?: string[]; /** Initial enabled state (default: true) */ enabled?: boolean; } export interface UpdateSkillInput { /** Skill ID to update */ id: string; /** Updated name */ name?: string; /** Updated description */ description?: string; /** Updated instructions */ instructions?: string; /** Updated tags */ tags?: string[]; /** Updated tools */ tools?: string[]; /** Updated enabled state */ enabled?: boolean; } export interface SearchSkillsInput { /** Free text query to search across name, description, instructions, tags */ query: string; /** Limit results */ limit?: number; /** Include disabled skills */ includeDisabled?: boolean; } export interface EnableSkillInput { /** Skill ID or name to enable */ skill: string; } export interface DisableSkillInput { /** Skill ID or name to disable */ skill: string; } export interface DeleteSkillInput { /** Skill ID to delete */ id: string; } export interface ListSkillsResult { skills: SkillSummary[]; total: number; } export interface SearchSkillsResult { /** Skills that match the query well */ matching: SkillSummary[]; /** Skills that might be relevant */ related: SkillSummary[]; total: number; } export interface EnableSkillResult { /** Skill ID */ id: string; /** Skill name */ name: string; /** The full instructions to use */ instructions: string; /** Additional setup instructions (if setup was called) */ setupInstructions?: string; /** Tools used by this skill */ tools?: string[]; /** Whether setup was executed */ setupExecuted: boolean; } export interface AddSkillResult { id: string; name: string; description: string; } export interface UpdateSkillResult { id: string; name: string; updated: boolean; } export type SkillEventType = 'skill_added' | 'skill_updated' | 'skill_deleted' | 'skill_enabled' | 'skill_disabled' | 'runtime_skill_registered' | 'runtime_skill_unregistered'; export interface SkillEvent { type: SkillEventType; skillId: string; timestamp: Date; data?: any; } /** * Skills API - Provides access to skill discovery, management, and enablement. * * Skills are instructions on how to accomplish tasks using tools. * They can be: * - Database-persisted: Created via add(), no setup/teardown * - Runtime-registered: Created via registerRuntime(), can have setup/teardown * * @example * ```typescript * // List all available skills * const { skills } = await ctx.majk.skills.list(); * * // Search for skills * const results = await ctx.majk.skills.search(conversationId, { query: 'code review' }); * * // Enable a skill (calls setup if available) * const result = await ctx.majk.skills.enable(context, { skill: 'code-review-mode' }); * console.log(result.instructions); * * // Register a runtime skill with setup/teardown * await ctx.majk.skills.registerRuntime({ * id: 'my-skill', * name: 'My Custom Skill', * description: 'Does something useful', * instructions: 'Follow these steps...', * enabled: true, * setup: async (ctx) => 'Additional context from setup', * teardown: async (ctx) => { cleanup(); } * }); * ``` */ export interface SkillsAPI { /** * List all available skills. * * @param conversationId - Optional conversation ID for scoped skills * @param includeDisabled - Include disabled skills in results * @returns List of skill summaries */ list(conversationId?: string, includeDisabled?: boolean): Promise; /** * Search skills by query. * * @param conversationId - Optional conversation ID for scoped skills * @param input - Search parameters * @returns Matching and related skills */ search(conversationId: string | undefined, input: SearchSkillsInput): Promise; /** * Get a skill by ID. * * @param skillId - The skill ID * @returns Full skill data or null if not found */ getById(skillId: string): Promise; /** * Add a new skill to the database. * * @param conversationId - Optional conversation ID for scoped skills * @param input - Skill data * @returns Created skill summary */ add(conversationId: string | undefined, input: AddSkillInput): Promise; /** * Update an existing skill in the database. * * @param input - Update data including skill ID * @returns Updated skill summary */ update(input: UpdateSkillInput): Promise; /** * Delete a skill from the database. * * @param input - Delete parameters * @returns True if deleted */ delete(input: DeleteSkillInput): Promise; /** * Enable a skill and get its instructions. * Calls the skill's setup() function if available. * * @param context - Skill context with conversation and project info * @param input - Enable parameters * @returns Skill instructions and setup result */ enable(context: SkillContext, input: EnableSkillInput): Promise; /** * Disable a skill. * * @param conversationId - Conversation ID * @param input - Disable parameters * @returns True if disabled */ disable(conversationId: string, input: DisableSkillInput): Promise; /** * Register a runtime skill (with optional setup/teardown). * Runtime skills are not persisted and exist only in memory. * * @param skill - Runtime skill definition */ registerRuntime(skill: RuntimeSkill): Promise; /** * Unregister a runtime skill. * * @param skillId - The skill ID to unregister * @returns True if the skill was found and removed */ unregisterRuntime(skillId: string): Promise; /** * Get a runtime skill by ID (if it exists). * * @param skillId - The skill ID * @returns Runtime skill or undefined */ getRuntime(skillId: string): Promise; /** * Subscribe to skill events. * * @param eventType - The event type to listen for * @param handler - Event handler function * @returns Unsubscribe function */ on(eventType: SkillEventType, handler: (event: SkillEvent) => void): Promise; } /** * Witness - Recursive structure for verification checks. * Used by delegation and batch services. */ export interface Witness { bash?: string | { command: string; stdout_contains?: string; stdout_not_contains?: string; stderr_contains?: string; exit_code?: number; }; file?: { path: string; contains?: string; not_contains?: string; exists?: boolean; json_path?: string; equals?: any; }; files?: string[]; http?: { url: string; method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD'; status?: number | number[]; body_contains?: string; headers?: Record; body?: any; }; llm?: { prompt: string; file?: string; context?: string; }; vision?: { image: string; checklist: string[]; context?: string; }; js?: { code?: string; file?: string; timeout?: number; }; message?: { contains?: string; index?: number; from?: 'user' | 'assistant' | 'any'; after_message?: number; }; all?: Witness[]; any?: Witness[]; } /** * Result from running a witness verification */ export interface WitnessResult { passed: boolean; evidence: string; strength: 'hard' | 'soft'; executionTimeMs: number; children?: WitnessResult[]; } export type DelegationTaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'blocked' | 'abandoned'; export interface DelegationTeammate { id: string; name: string; skills?: string[]; description?: string; } export interface DelegationTaskResult { success: boolean; summary: string; witnessResults: Array<{ witness: string; passed: boolean; evidence: string; }>; verification?: WitnessResult; } export interface DelegationTaskBlocker { summary: string; task: string; witness: Witness; evidence?: Witness; assignTo: string; reportedAt: Date | string; blockerTaskId?: string; } export interface DelegationRecentMessage { role: string; content: string; timestamp: Date | string; } export interface DelegationTaskStatusOutput { taskId: string; status: DelegationTaskStatus; teammateId: string; teammateName: string; result?: DelegationTaskResult; blocker?: DelegationTaskBlocker; recentMessages?: DelegationRecentMessage[]; progress?: { messageCount: number; durationMs: number; }; } export interface DelegationBlockerInfo { taskId: string; teammateId: string; teammateName: string; task: string; blocker: DelegationTaskBlocker; reportedAt: string; durationMs: number; } /** * Delegation API - Multi-agent task delegation with witness-based verification. * * @example * ```typescript * // List available teammates * const { teammates } = await ctx.majk.delegation.list_teammates(); * * // Delegate a task * const result = await ctx.majk.delegation.delegate_task({ * teammate: 'code-reviewer', * task: 'Review the auth module for security issues', * witness: { bash: 'npm test' } * }); * * // Wait for completion * const status = await ctx.majk.delegation.await_task({ * taskId: result.taskId * }); * ``` */ export interface DelegationAPI { /** * List all available teammates that can be delegated tasks to. */ list_teammates(): Promise<{ teammates: DelegationTeammate[]; count: number; _hint: string; }>; /** * Delegate a task to a teammate asynchronously. * Returns immediately with a task ID. The task runs in the background. */ delegate_task(input: { teammate: string; task: string; context?: Witness; witness: Witness; workingDirectory?: string; /** * Run the task in the background (hidden from UI). * Use this for batch operations or when you want to run multiple tasks without UI clutter. */ background?: boolean; /** * If true, use the task field as-is without any enhancement. * By default, tasks are enhanced with context, witness criteria, and reporting instructions. * When using rawPrompt, YOU must include reporting instructions (use get_reporting_instructions to get them). */ rawPrompt?: boolean; }): Promise<{ taskId: string; teammateId: string; teammateName: string; conversationId: string; status: 'running'; _hint: string; }>; /** * Get the standard reporting instructions template for delegated tasks. * * Use this when using rawPrompt: true in delegate_task and you want to include * the standard reporting instructions in your custom prompt. * * The instructions tell the delegate how to report completion (report_done) * or blockers (report_blocker). */ get_reporting_instructions(input?: { /** Optional task ID to include in the instructions */ taskId?: string; }): Promise<{ /** The reporting instructions template markdown */ instructions: string; /** Names of the delegate tools */ toolNames: { reportDone: string; reportBlocker: string; checkWitness: string; }; _hint: string; }>; /** * Check the current status of a delegated task. */ check_task_status(input: { taskId: string; messageCount?: number; }): Promise; /** * Wait for a task to complete. * Blocks until the task finishes or timeout is reached. */ await_task(input: { taskId: string; timeoutMs?: number; }): Promise; /** * Wait for multiple tasks to complete (fan-out/fan-in pattern). */ await_tasks(input: { taskIds: string[]; timeoutMs?: number; }): Promise<{ results: DelegationTaskStatusOutput[]; summary: { total: number; completed: number; failed: number; blocked: number; stillRunning: number; }; allCompleted: boolean; allSucceeded: boolean; }>; /** * Run a witness to verify something right now. */ check_witness(input: { witness: Witness; workingDirectory?: string; }): Promise; /** * List all currently blocked tasks with their blocker details. */ get_blockers(input?: { teammateId?: string; assignedTo?: string; }): Promise<{ blockers: DelegationBlockerInfo[]; count: number; }>; /** * Resolve a blocker by updating the task, witness, or sending instructions. */ resolve_blocker(input: { taskId: string; action: 'update_task' | 'update_witness' | 'send_instruction' | 'unblock'; newTask?: string; newWitness?: Witness; instruction?: string; resolution?: string; }): Promise<{ taskId: string; action: string; previousStatus: DelegationTaskStatus; newStatus: DelegationTaskStatus; message: string; }>; } export type BatchJobStatus = 'pending' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled'; export type BatchItemStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped'; export interface BatchInputSource { type: 'list' | 'directory' | 'glob'; items?: any[]; path?: string; recursive?: boolean; extensions?: string[]; exclude?: string[]; pattern?: string; basePath?: string; ignore?: string[]; } export interface BatchProcessorConfig { type: 'teammate' | 'rpc' | 'witness' | 'script'; teammateId?: string; taskTemplate?: string; context?: Witness; witness?: Witness; workingDirectory?: string; taskTimeoutMs?: number; pluginId?: string; serviceName?: string; functionName?: string; input?: Record; code?: string; file?: string; timeoutMs?: number; } export interface BatchExecutionConfig { maxParallelism?: number; itemTimeoutMs?: number; jobTimeoutMs?: number; retry?: { maxAttempts?: number; backoff?: 'none' | 'fixed' | 'linear' | 'exponential'; initialDelayMs?: number; maxDelayMs?: number; jitter?: boolean; }; } export interface BatchProgress { totalItems: number; completedItems: number; failedItems: number; skippedItems?: number; runningItems?: number; pendingItems?: number; } export interface BatchJob { id: string; name: string; status: BatchJobStatus; statusReason?: string; createdAt: Date | string; startedAt?: Date | string; completedAt?: Date | string; progress: BatchProgress; resultSummary?: any; tags?: string[]; } export interface BatchJobItem { id: string; index: number; status: BatchItemStatus; data: any; result?: any; error?: string; errorCode?: string; attempts?: number; durationMs?: number; } /** * Batch API - Batch processing for large sets of items. * * @example * ```typescript * // Create a batch job * const { job } = await ctx.majk.batch.create_batch_job({ * name: 'Process files', * input: { source: { type: 'glob', pattern: 'src/**\/*.ts' } }, * processor: { * type: 'teammate', * teammateId: 'code-reviewer', * taskTemplate: 'Review {{item}}' * }, * autoStart: true * }); * * // Wait for completion * const result = await ctx.majk.batch.await_batch_job({ jobId: job.id }); * ``` */ export interface BatchAPI { /** * Create a new batch processing job. */ create_batch_job(input: { name: string; description?: string; input: { source: BatchInputSource; transformTemplate?: string; skipIfTemplate?: string; limit?: number; }; processor: BatchProcessorConfig; execution?: BatchExecutionConfig; tags?: string[]; metadata?: Record; autoStart?: boolean; }): Promise<{ job: BatchJob; _hint: string; }>; /** * Start a pending batch job. */ start_batch_job(input: { jobId: string; }): Promise<{ job: BatchJob; _hint: string; }>; /** * Pause a running batch job. */ pause_batch_job(input: { jobId: string; reason?: string; }): Promise<{ job: BatchJob; _hint: string; }>; /** * Resume a paused batch job. */ resume_batch_job(input: { jobId: string; }): Promise<{ job: BatchJob; }>; /** * Cancel a batch job. */ cancel_batch_job(input: { jobId: string; }): Promise<{ job: BatchJob; }>; /** * Get the current status and progress of a batch job. */ check_batch_job(input: { jobId: string; includeFailedItems?: boolean; failedItemsLimit?: number; }): Promise<{ job: { id: string; name: string; status: BatchJobStatus; statusReason?: string; createdAt: Date | string; startedAt?: Date | string; completedAt?: Date | string; }; progress: BatchProgress; resultSummary?: any; failedItems?: Array<{ id: string; index: number; data: any; error?: string; errorCode?: string; }>; }>; /** * Wait for a batch job to complete. */ await_batch_job(input: { jobId: string; timeoutMs?: number; ignoreBlockers?: boolean; }): Promise<{ job: { id: string; name: string; status: BatchJobStatus; statusReason?: string; createdAt: Date | string; startedAt?: Date | string; completedAt?: Date | string; }; resultSummary?: any; finalProgress: BatchProgress; hasBlockers?: boolean; blockedCount?: number; }>; /** * List batch jobs with optional filters. */ list_batch_jobs(input?: { status?: BatchJobStatus | BatchJobStatus[]; tags?: string[]; limit?: number; offset?: number; }): Promise<{ jobs: Array<{ id: string; name: string; status: BatchJobStatus; progress: { total: number; completed: number; failed: number; }; createdAt: Date | string; tags?: string[]; }>; total: number; hasMore: boolean; }>; /** * Get items from a batch job with optional status filter. */ get_batch_job_items(input: { jobId: string; status?: BatchItemStatus | BatchItemStatus[]; limit?: number; offset?: number; }): Promise<{ items: BatchJobItem[]; total: number; hasMore: boolean; }>; /** * Get blocked items from a batch job. */ get_blocked_batch_items(input: { jobId: string; limit?: number; }): Promise<{ items: Array<{ id: string; index: number; data: any; error?: string; errorCode?: string; originalData?: any; }>; total: number; _hint?: string; }>; /** * Create a new job to replay failed items from a completed job. */ replay_failed_batch_items(input: { jobId: string; }): Promise<{ job: BatchJob; _hint: string; }>; /** * Clone a batch job to create a new one with the same configuration. */ clone_batch_job(input: { jobId: string; name?: string; tags?: string[]; }): Promise<{ job: BatchJob; _hint: string; }>; } export interface ReportSummary { id: string; path: string; uri: string; title?: string; tags?: string[]; status?: string; hasWitness: boolean; preview?: string; updatedAt: string; viewPath?: string; } export interface ReportValidation { status: 'valid' | 'invalid' | 'skipped' | 'no-witness'; witness?: WitnessResult; } export interface ReportWriteResult { id: string; path: string; uri: string; title?: string; hasWitness: boolean; created: boolean; } export interface ReportReadResult { id: string; path: string; uri: string; title?: string; tags?: string[]; status?: string; content: string; totalLines: number; range?: { start: number; end: number; }; validation: ReportValidation; updatedAt: string; viewPath?: string; viewName?: string; } export interface ReportView { id: string; name: string; isDefault: boolean; reportCount: number; } export interface ReportViewTreeNode { path: string; name: string; report?: ReportSummary; children: ReportViewTreeNode[]; } export interface ReportEdit { line?: number; lines?: [number, number]; content?: string; after?: number; delete?: true; } /** * Reports API - Knowledge management with witness-based validation. * * @example * ```typescript * // Write a report * const result = await ctx.majk.reports.write_report({ * path: '/research/findings.md', * content: '# Findings\n...', * tags: ['research'] * }); * * // Read a report * const report = await ctx.majk.reports.read_report({ * report: result.id * }); * * // List reports * const { reports } = await ctx.majk.reports.list_reports({ * pathPrefix: '/research/' * }); * ``` */ export interface ReportsAPI { /** * Write a report to the knowledge base. */ write_report(input: { content: string; path: string; title?: string; partOf?: { parent: string; placeholder?: string; }; refs?: string[]; tags?: string[]; status?: string; witness?: Witness; }): Promise; /** * Read a report with embedded content expansion. */ read_report(input: { report: string; view?: string; expand?: 'link' | 'inline' | 'inline-linked'; expandDepth?: number; offset?: number; limit?: number; validate?: boolean; workingDirectory?: string; }): Promise; /** * List and search reports. */ list_reports(input?: { view?: string; pathPrefix?: string; tags?: string[]; status?: string; hasWitness?: boolean; search?: string; limit?: number; offset?: number; }): Promise<{ reports: ReportSummary[]; total: number; hasMore: boolean; }>; /** * Delete a report from the knowledge base. */ delete_report(input: { report: string; }): Promise<{ deleted: boolean; }>; /** * Batch move reports. */ reorganize_reports(input: { moves: Array<{ from: string; to: string; }>; }): Promise<{ message: string; moved: Array<{ from: string; to: string; id: string; }>; structure: Record; }>; /** * Start a new report from a template. */ start_report(input: { template: string; topic: string; sections?: Record; refs?: Record; validateOnUpdate?: boolean; }): Promise<{ handle: string; preview: string; missing: { sections: string[]; refs: string[]; }; warnings?: string[]; }>; /** * Update a draft report with new sections or refs. */ update_draft(input: { handle: string; sections?: Record; refs?: Record; }): Promise<{ preview: string; missing: { sections: string[]; refs: string[]; }; validation?: any; }>; /** * Preview a draft report with optional validation. */ preview_draft(input: { handle: string; validate?: boolean; }): Promise<{ rendered: string; missing: { sections: string[]; refs: string[]; }; validation?: any; ready: boolean; }>; /** * Finalize a draft report - validate and commit. */ finalize_report(input: { handle: string; force?: boolean; }): Promise<{ success: boolean; report?: ReportWriteResult; validation?: any; error?: { code: string; message: string; }; suggestions?: string[]; }>; /** * Update an existing report with line-based edits. */ update_report(input: { report: string; edits: ReportEdit[]; validate?: boolean; }): Promise<{ report: ReportWriteResult; validation?: { passed: boolean; status: string; message?: string; }; }>; /** * Create a new view with an LLM-powered organization strategy. */ create_view(input: { name: string; philosophy: string; categorizeExisting?: boolean; }): Promise<{ id: string; name: string; reportsCategorized?: number; }>; /** * List all views in the conversation. */ list_views(): Promise<{ views: ReportView[]; }>; /** * Get the tree structure of a view. */ get_view_structure(input: { view: string; }): Promise<{ viewId: string; viewName: string; tree: ReportViewTreeNode; reportCount: number; }>; /** * Delete a view (not the default "All" view). */ delete_view(input: { view: string; }): Promise<{ deleted: boolean; viewName: string; }>; /** * Import a file into the knowledge base. */ import_document(input: { file: string; topic?: string; title?: string; tags?: string[]; status?: string; cleanup?: boolean; }): Promise<{ success: boolean; imported: { source: string; handler: string; reports: Array<{ id: string; path: string; title: string; partOf?: string; }>; stats: { totalReports: number; totalCharacters: number; sections?: number; }; sourceDeleted?: boolean; cleanupError?: string; }; }>; /** * Export a report to a file. */ export_report(input: { report: string; outputPath: string; format?: 'markdown' | 'html' | 'pdf' | 'docx'; mode?: 'single' | 'hierarchy' | 'inlined'; templateId?: string; title?: string; includeFrontmatter?: boolean; }): Promise<{ success: boolean; outputPath: string; reportsExported: number; totalSize: number; error?: string; files?: string[]; }>; /** * Export all reports to a directory. */ export_all_reports(input: { outputDir: string; format?: 'markdown' | 'html' | 'pdf' | 'docx'; templateId?: string; includeFrontmatter?: boolean; }): Promise<{ message: string; outputDir: string; reportsExported: number; totalSize: number; files: string[]; errors?: string[]; }>; /** * List available export templates. */ list_export_templates(): Promise<{ templates: Array<{ id: string; name: string; description?: string; category: string; }>; total: number; }>; } export interface DiscoveredFunction { name: string; description: string; inputSchema: Record; identityRequirements?: Array<{ identityType: string; required: boolean; description?: string; }>; } export interface DiscoveredService { pluginId: string; serviceName: string; displayName: string; description: string; isBuiltin: boolean; category?: string; functionCount: number; functions: DiscoveredFunction[]; } /** * Tool Discovery API - Discover available service functions and their schemas. * * @example * ```typescript * // Discover all tools * const { services, summary } = await ctx.majk.toolDiscovery.discover_tools(); * * // Get schema for a specific function * const schema = await ctx.majk.toolDiscovery.get_tool_schema({ * functionName: 'delegate_task' * }); * * // Invoke a discovered tool dynamically * const result = await ctx.majk.toolDiscovery.invoke_tool({ * functionName: 'list_teammates', * parameters: {} * }); * ``` */ export interface ToolDiscoveryAPI { /** * Discover available service functions that can be called. */ discover_tools(input?: { pluginId?: string; category?: string; functionNameContains?: string; builtinOnly?: boolean; requiresIdentity?: string; }): Promise<{ services: DiscoveredService[]; summary: { totalServices: number; totalFunctions: number; byCategory: Record; byPlugin: Record; }; }>; /** * Get the detailed input schema for a specific function. */ get_tool_schema(input: { functionName: string; }): Promise<{ function: DiscoveredFunction; service: { pluginId: string; serviceName: string; displayName: string; category?: string; }; }>; /** * Get a simple list of all available function names. */ list_tool_names(): Promise<{ functions: string[]; count: number; }>; /** * List all available tool categories. */ list_tool_categories(): Promise<{ categories: string[]; count: number; }>; /** * Get RPC invocation information for a specific function. */ get_rpc_invocation_info(input: { functionName: string; }): Promise<{ rpcServiceName: string; functionName: string; inputSchema: Record; outputSchema?: Record; readOnly: boolean; service: { pluginId: string; serviceName: string; displayName: string; category?: string; }; identityRequirements?: Array<{ identityType: string; required: boolean; description?: string; }>; }>; /** * Invoke any registered service function by name with parameters. */ invoke_tool(input: { functionName: string; parameters?: Record; timeoutMs?: number; }): Promise; } export interface ScriptTraceSummary { totalCalls: number; readsExecuted: number; writesMocked: number; errorsEncountered: number; totalDurationMs: number; consoleOutputLines: number; aiMocksUsed: number; } export interface ScriptTraceEvent { seq: number; timestamp: number; type: string; summary: string; details?: any; } export interface ScriptToolCallRecord { seq: number; service: string; function: string; params: Record; result?: any; error?: string; durationMs: number; wasMocked: boolean; mockSource?: string; } export interface ScriptError { message: string; name?: string; line?: number; column?: number; codeSnippet?: string; } /** * Scripting API - Execute JavaScript scripts that orchestrate tool calls. * * @example * ```typescript * // Execute a script * const result = await ctx.majk.scripting.execute_script({ * code: ` * const reports = await tools.ReportsService.list_reports({ limit: 10 }); * console.log('Found', reports.length, 'reports'); * return { count: reports.length }; * `, * dryRun: true * }); * * // Re-run with new parameters * const result2 = await ctx.majk.scripting.execute_script({ * rerun: result.traceId, * params: { count: 20 } * }); * ``` */ export interface ScriptingAPI { /** * Execute JavaScript that orchestrates tool calls. */ execute_script(input: { code?: string; rerun?: string; params?: Record; dryRun?: boolean; dryRunOptions?: { maxAIMocks?: number; }; timeoutMs?: number; }): Promise<{ success: boolean; result?: any; error?: ScriptError; traceId: string; traceFormatted: string; trace: { summary: ScriptTraceSummary; events: ScriptTraceEvent[]; toolCalls?: ScriptToolCallRecord[]; }; }>; /** * Get full details for a specific tool call from a previous script execution. */ expand_trace(input: { traceId: string; callSeq: number; }): Promise<{ call: ScriptToolCallRecord; fullParams: string; fullResult: string; functionSchema?: any; }>; /** * List recent script execution traces. */ list_traces(): Promise<{ traces: Array<{ id: string; storedAt: string; summary: { success: boolean; totalCalls: number; durationMs: number; dryRun: boolean; }; }>; count: number; }>; /** * Get the full formatted trace output for a previous script execution. */ get_trace_formatted(input: { traceId: string; }): Promise<{ traceFormatted: string; success: boolean; totalCalls: number; durationMs: number; }>; } /** * Parameter types for SQL operations. * Supports both positional (array) and named (object) parameter binding. */ export type PluginSQLParams = unknown[] | Record; /** * A single schema migration. * Migrations are applied in ascending version order and each version is run * exactly once — safe to call migrate() on every plugin startup. */ export interface PluginSQLMigration { /** * Monotonically increasing version number (e.g. 1, 2, 3...). * Never reuse or lower a version number. */ version: number; /** * SQL to execute when this migration is applied. * May contain multiple statements separated by semicolons. */ up: string; /** * Optional SQL to execute when rolling back this migration. * Currently not used by the migration system, but may be used for development tooling. */ down?: string; } /** * Result returned from INSERT / UPDATE / DELETE operations. */ export interface PluginSQLRunResult { /** Number of rows inserted, updated, or deleted. */ changes: number; /** Row ID of the last inserted row (undefined if not applicable). */ lastInsertRowid?: number; } /** * Information about a database column. */ export interface PluginSQLColumnInfo { /** Column name */ name: string; /** SQLite type declaration (TEXT, INTEGER, REAL, BLOB, etc.) */ type: string; /** Whether the column allows NULL values */ nullable: boolean; /** Default value as a string, or null if no default */ defaultValue: string | null; /** Whether this column is part of the primary key */ primaryKey: boolean; /** Whether this column is auto-incrementing (INTEGER PRIMARY KEY) */ autoIncrement: boolean; } /** * Information about a database index. */ export interface PluginSQLIndexInfo { /** Index name */ name: string; /** Column names that make up this index, in order */ columns: string[]; /** Whether this is a unique index */ unique: boolean; } /** * Transaction-scoped SQL API. * All operations within a transaction are committed atomically on success, * or rolled back completely on error. */ export interface PluginSQLTx { /** * Execute a SELECT (or any statement returning rows) and return all results. * Same as the main API but executes within the current transaction. */ query>(sql: string, params?: PluginSQLParams): Promise; /** * Execute a SELECT and return the first result, or null if no rows match. * Same as the main API but executes within the current transaction. */ queryOne>(sql: string, params?: PluginSQLParams): Promise; /** * Execute an INSERT, UPDATE, or DELETE and return metadata about the operation. * Same as the main API but executes within the current transaction. */ run(sql: string, params?: PluginSQLParams): Promise; /** * Execute the same SQL statement multiple times with different parameter sets. * Same as the main API but executes within the current transaction. */ batch(sql: string, paramRows: PluginSQLParams[]): Promise; /** * Get list of table names in the database. * Same as the main API but executes within the current transaction. */ tables(): Promise; /** * Get column information for a specific table. * Same as the main API but executes within the current transaction. */ columns(table: string): Promise; /** * Get index information for a specific table. * Same as the main API but executes within the current transaction. */ indexes(table: string): Promise; } /** * Raw SQL API for plugin-local SQLite access. * * All operations target an isolated database file owned exclusively by this * plugin. No other plugin or Majk system has access to it. */ export interface PluginSQLAPI { /** * Apply a list of schema migrations in version order. * * Only migrations whose version is higher than the last applied version * are executed. Already-applied migrations are skipped automatically. * It is safe — and recommended — to call this on every plugin startup. * * Migrations are applied inside individual transactions so a failed * migration does not corrupt previously applied schema changes. * * @param migrations - Array of migrations. Order does not matter — they are * sorted by version before execution. * * @example * await ctx.majk.sql.migrate([ * { version: 1, up: 'CREATE TABLE items (id INTEGER PRIMARY KEY, label TEXT NOT NULL)' }, * { version: 2, up: 'ALTER TABLE items ADD COLUMN created_at INTEGER' }, * ]); */ migrate(migrations: PluginSQLMigration[]): Promise; /** * Execute a SELECT (or any statement returning rows) and return all results. * * @param sql - SQL query. Use ? for positional parameters or :name for named parameters. * @param params - Values to bind to placeholders. Array for positional, object for named. * @returns Array of row objects. Empty array if no rows match. * * @example * // Positional parameters * const rows = await ctx.majk.sql.query<{ id: number; name: string }>( * 'SELECT id, name FROM users WHERE active = ?', [1] * ); * * // Named parameters * const rows = await ctx.majk.sql.query<{ id: number; name: string }>( * 'SELECT id, name FROM users WHERE active = :active', { active: 1 } * ); */ query>(sql: string, params?: PluginSQLParams): Promise; /** * Execute a SELECT and return the first result, or null if no rows match. * * @param sql - SQL query. Use ? for positional parameters or :name for named parameters. * @param params - Values to bind to placeholders. Array for positional, object for named. * @returns First row object, or null if no rows match. * * @example * const user = await ctx.majk.sql.queryOne<{ name: string }>( * 'SELECT name FROM users WHERE id = ?', [123] * ); * if (user) { * console.log('Found user:', user.name); * } */ queryOne>(sql: string, params?: PluginSQLParams): Promise; /** * Execute an INSERT, UPDATE, or DELETE and return metadata about the operation. * * @param sql - SQL statement. Use ? for positional parameters or :name for named parameters. * @param params - Values to bind to placeholders. Array for positional, object for named. * @returns Object with `changes` (affected row count) and `lastInsertRowid`. * * @example * const result = await ctx.majk.sql.run( * 'INSERT INTO events (name, ts) VALUES (?, ?)', ['startup', Date.now()] * ); * console.log('Inserted row id:', result.lastInsertRowid); */ run(sql: string, params?: PluginSQLParams): Promise; /** * Execute the same SQL statement multiple times with different parameter sets. * All operations are performed atomically within a single transaction. * * @param sql - SQL statement to execute repeatedly. * @param paramRows - Array of parameter sets to bind to the statement. * @returns Array of results, one for each parameter set. * * @example * const results = await ctx.majk.sql.batch( * 'INSERT INTO events (name, ts) VALUES (?, ?)', * [['click', 1000], ['hover', 2000], ['scroll', 3000]] * ); * console.log('Inserted', results.length, 'events'); */ batch(sql: string, paramRows: PluginSQLParams[]): Promise; /** * Execute a function inside an atomic SQLite transaction. * * All SQL calls made within `fn` are committed together on success, or * fully rolled back if `fn` throws or rejects. The resolved value of `fn` * is returned. * * The transaction function receives a `PluginSQLTx` object that provides * the same query/run/batch/tables/columns/indexes methods as the main API, * but scoped to the current transaction. * * @param fn - Async function containing the transactional work. * @returns A Promise that resolves to whatever `fn` returns. * * @example * const balances = await ctx.majk.sql.transaction(async (tx) => { * const alice = await tx.run('INSERT INTO accounts (name, balance) VALUES (?, ?)', ['Alice', 100]); * const bob = await tx.run('INSERT INTO accounts (name, balance) VALUES (?, ?)', ['Bob', 50]); * * // Transfer money between accounts * await tx.run('UPDATE accounts SET balance = balance - ? WHERE name = ?', [25, 'Alice']); * await tx.run('UPDATE accounts SET balance = balance + ? WHERE name = ?', [25, 'Bob']); * * return await tx.query<{ name: string; balance: number }>('SELECT name, balance FROM accounts'); * }); */ transaction(fn: (tx: PluginSQLTx) => Promise): Promise; /** * Get list of table names in the database. * Excludes internal Majk tables (prefixed with _majk_) and SQLite system tables. * * @returns Array of table names sorted alphabetically. * * @example * const tables = await ctx.majk.sql.tables(); * console.log('Plugin tables:', tables); */ tables(): Promise; /** * Get column information for a specific table. * * @param table - Name of the table to inspect. * @returns Array of column information objects. * * @example * const columns = await ctx.majk.sql.columns('users'); * columns.forEach(col => { * console.log(`${col.name}: ${col.type}, nullable: ${col.nullable}`); * }); */ columns(table: string): Promise; /** * Get index information for a specific table. * * @param table - Name of the table to inspect. * @returns Array of index information objects. * * @example * const indexes = await ctx.majk.sql.indexes('users'); * indexes.forEach(idx => { * console.log(`Index ${idx.name} on columns: ${idx.columns.join(', ')}, unique: ${idx.unique}`); * }); */ indexes(table: string): Promise; } export interface PluginSelfAPI { readonly pluginId: string; teammates(): Promise; getDefaultTeammate(): Promise; conversations(filter?: PluginConversationFilter): Promise; startChat(options: PluginStartChatOptions): Promise; attachChat(conversationId: string): Promise; } export interface PluginTeammate { id: string; name: string; } export interface PluginStartChatOptions { message: string; title?: string; /** Teammate to use. Defaults to the plugin's registered default teammate. */ teammateId?: string; projectId?: string; workingDirectory?: string; tags?: string[]; metadata?: Record; } export interface PluginChatHandle { readonly conversationId: string; readonly teammateId: string | undefined; dispose(): void; getMessages(options?: { afterSeq?: number; limit?: number; }): Promise; send(message: string): Promise; waitForNextResponse(options?: { timeoutMs?: number; }): Promise; waitForCompletion(options?: { timeoutMs?: number; }): Promise<{ status: 'completed' | 'failed' | 'cancelled'; lastMessage: PluginMessage | null; }>; onMessage(callback: (event: PluginMessageEvent) => void | Promise, options?: { fromSeq?: number; }): PluginSubscription; promote(): Promise; hide(): Promise; } export interface PluginSubscription { unsubscribe(): void; readonly disposed: boolean; } export interface PluginMessage { id: string; seq: number; role: 'user' | 'assistant' | 'tool_use' | 'tool_result'; content: string; createdAt: Date; } export interface PluginConversationSummary { id: string; title: string; status: 'active' | 'completed' | 'failed' | 'cancelled'; teammateId: string | undefined; createdAt: Date; lastMessageAt: Date | null; lastMessagePreview: string | null; metadata: Record; } export interface PluginConversationFilter { status?: 'active' | 'completed' | 'failed' | 'cancelled'; teammateId?: string; tags?: string[]; since?: Date; limit?: number; } export type PluginMessageEvent = { type: 'message_created'; messageId: string; seq: number; role: string; content: string; } | { type: 'message_updated'; messageId: string; seq: number; role: string; content: string; } | { type: 'conversation_complete'; status: 'completed' | 'failed' | 'cancelled'; }; export interface MajkInterface { readonly version: string; readonly config: ConfigAPI; readonly plugins: PluginManagementAPI; readonly secrets: SecretsAPI; readonly tasks: TaskAPI; readonly eventBus: EventBusAPI; readonly auth: AuthAPI; readonly ai: AIAPI; readonly conversations: ConversationAPI; readonly todos: TodoAPI; readonly projects: ProjectAPI; readonly teammates: TeammateAPI; readonly mcpServers: MCPServerAPI; readonly knowledge: KnowledgeAPI; readonly agents: AgentAPI; readonly skills: SkillsAPI; readonly sql: PluginSQLAPI; /** * Plugin identity-scoped API. * Provides the plugin with easy access to its own conversations, * teammates, and background chat management. * * @example * const chat = await ctx.majk.me.startChat({ message: 'Analyze this data' }); * const { lastMessage } = await chat.waitForCompletion(); * chat.dispose(); */ readonly me: PluginSelfAPI; readonly batch: BatchAPI; readonly delegation: DelegationAPI; readonly reports: ReportsAPI; readonly toolDiscovery: ToolDiscoveryAPI; readonly scripting: ScriptingAPI; } export {}; //# sourceMappingURL=majk-interface-types.d.ts.map