@hailer/mcp 0.2.7 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.claude/skills/client-bot-architecture/skill.md +340 -0
  2. package/.claude/skills/publish-hailer-app/SKILL.md +11 -0
  3. package/dist/app.d.ts +1 -1
  4. package/dist/app.js +116 -84
  5. package/dist/bot/chat-bot.d.ts +31 -0
  6. package/dist/bot/chat-bot.js +356 -0
  7. package/dist/cli.d.ts +9 -1
  8. package/dist/cli.js +71 -2
  9. package/dist/config.d.ts +15 -2
  10. package/dist/config.js +53 -3
  11. package/dist/lib/logger.js +11 -11
  12. package/dist/mcp/hailer-clients.js +12 -11
  13. package/dist/mcp/tool-registry.d.ts +4 -0
  14. package/dist/mcp/tool-registry.js +78 -1
  15. package/dist/mcp/tools/activity.js +47 -0
  16. package/dist/mcp/tools/discussion.js +44 -1
  17. package/dist/mcp/tools/metrics.d.ts +13 -0
  18. package/dist/mcp/tools/metrics.js +546 -0
  19. package/dist/mcp/tools/user.d.ts +1 -0
  20. package/dist/mcp/tools/user.js +94 -1
  21. package/dist/mcp/tools/workflow.js +109 -40
  22. package/dist/mcp/webhook-handler.js +7 -4
  23. package/dist/mcp-server.js +22 -6
  24. package/dist/stdio-server.d.ts +14 -0
  25. package/dist/stdio-server.js +101 -0
  26. package/package.json +6 -6
  27. package/scripts/test-hal-tools.ts +154 -0
  28. package/test-billing-server.js +136 -0
  29. package/dist/lib/discussion-lock.d.ts +0 -42
  30. package/dist/lib/discussion-lock.js +0 -110
  31. package/dist/mcp/tools/bot-config/constants.d.ts +0 -23
  32. package/dist/mcp/tools/bot-config/constants.js +0 -94
  33. package/dist/mcp/tools/bot-config/core.d.ts +0 -253
  34. package/dist/mcp/tools/bot-config/core.js +0 -2456
  35. package/dist/mcp/tools/bot-config/index.d.ts +0 -10
  36. package/dist/mcp/tools/bot-config/index.js +0 -59
  37. package/dist/mcp/tools/bot-config/tools.d.ts +0 -7
  38. package/dist/mcp/tools/bot-config/tools.js +0 -15
  39. package/dist/mcp/tools/bot-config/types.d.ts +0 -50
  40. package/dist/mcp/tools/bot-config/types.js +0 -6
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Mock Token Billing Server for Testing
3
+ *
4
+ * Usage:
5
+ * node test-billing-server.js
6
+ *
7
+ * Endpoints:
8
+ * POST /balance - Check workspace balance
9
+ * POST /burn - Burn tokens (deducts from balance)
10
+ *
11
+ * Configure in .env.local:
12
+ * TOKEN_BILLING_ENABLED=true
13
+ * TOKEN_BALANCE_ENDPOINT=http://localhost:3099/balance
14
+ * TOKEN_BURN_ENDPOINT=http://localhost:3099/burn
15
+ */
16
+
17
+ const http = require('http');
18
+
19
+ // Starting balance per workspace (simulates real billing)
20
+ const STARTING_BALANCE = 10.00;
21
+
22
+ // Track balance per workspace
23
+ const workspaceBalances = new Map();
24
+
25
+ // Get or initialize workspace balance
26
+ function getBalance(workspaceId) {
27
+ if (!workspaceBalances.has(workspaceId)) {
28
+ workspaceBalances.set(workspaceId, STARTING_BALANCE);
29
+ }
30
+ return workspaceBalances.get(workspaceId);
31
+ }
32
+
33
+ // Deduct from workspace balance
34
+ function deductBalance(workspaceId, amount) {
35
+ const current = getBalance(workspaceId);
36
+ const newBalance = current - amount;
37
+ workspaceBalances.set(workspaceId, newBalance);
38
+ return newBalance;
39
+ }
40
+
41
+ // Track total burned across all workspaces
42
+ let totalBurned = 0;
43
+
44
+ const server = http.createServer((req, res) => {
45
+ res.setHeader('Content-Type', 'application/json');
46
+
47
+ let body = '';
48
+ req.on('data', chunk => body += chunk);
49
+ req.on('end', () => {
50
+ let data = {};
51
+ try {
52
+ data = JSON.parse(body || '{}');
53
+ } catch (e) {
54
+ res.statusCode = 400;
55
+ res.end(JSON.stringify({ error: 'Invalid JSON' }));
56
+ return;
57
+ }
58
+
59
+ const timestamp = new Date().toISOString().substring(11, 19);
60
+
61
+ if (req.url === '/balance') {
62
+ const balance = getBalance(data.workspaceId);
63
+ const isNegative = balance < 0;
64
+
65
+ console.log(`[${timestamp}] BALANCE CHECK`);
66
+ console.log(` Workspace: ${data.workspaceId}`);
67
+ console.log(` Balance: $${balance.toFixed(8)} ${isNegative ? '(NEGATIVE - will reject)' : '(OK)'}`);
68
+ console.log('');
69
+
70
+ res.end(JSON.stringify({
71
+ workspaceId: data.workspaceId,
72
+ balance: balance
73
+ }));
74
+ }
75
+ else if (req.url === '/burn') {
76
+ const cost = data.costUsd || 0;
77
+ const newBalance = deductBalance(data.workspaceId, cost);
78
+ totalBurned += cost;
79
+
80
+ console.log(`[${timestamp}] TOKEN BURN`);
81
+ console.log(` Workspace: ${data.workspaceId}`);
82
+ console.log(` Cost: $${cost.toFixed(8)}`);
83
+ console.log(` Input: ${data.inputTokens} tokens`);
84
+ console.log(` Output: ${data.outputTokens} tokens`);
85
+ console.log(` Cache Write: ${data.cacheCreationTokens} tokens`);
86
+ console.log(` Cache Read: ${data.cacheReadTokens} tokens`);
87
+ console.log(` Session: ${data.sessionId || 'N/A'}`);
88
+ console.log(` Activity: ${data.activityId || 'N/A'}`);
89
+ console.log(` ─────────────────────────────`);
90
+ console.log(` New Balance: $${newBalance.toFixed(8)}`);
91
+ console.log(` Total burned: $${totalBurned.toFixed(8)}`);
92
+ console.log('');
93
+
94
+ res.end(JSON.stringify({ success: true, newBalance }));
95
+ }
96
+ else if (req.url === '/reset') {
97
+ // Reset endpoint for testing
98
+ const workspaceId = data.workspaceId;
99
+ const newBalance = data.balance !== undefined ? data.balance : STARTING_BALANCE;
100
+ workspaceBalances.set(workspaceId, newBalance);
101
+
102
+ console.log(`[${timestamp}] BALANCE RESET`);
103
+ console.log(` Workspace: ${workspaceId}`);
104
+ console.log(` New Balance: $${newBalance.toFixed(8)}`);
105
+ console.log('');
106
+
107
+ res.end(JSON.stringify({ success: true, balance: newBalance }));
108
+ }
109
+ else {
110
+ res.statusCode = 404;
111
+ res.end(JSON.stringify({ error: 'Not found' }));
112
+ }
113
+ });
114
+ });
115
+
116
+ const PORT = 3099;
117
+
118
+ server.listen(PORT, () => {
119
+ console.log('═══════════════════════════════════════════');
120
+ console.log(' Mock Token Billing Server');
121
+ console.log('═══════════════════════════════════════════');
122
+ console.log(` Running on: http://localhost:${PORT}`);
123
+ console.log(` Starting balance: $${STARTING_BALANCE.toFixed(2)}`);
124
+ console.log('');
125
+ console.log(' Endpoints:');
126
+ console.log(` POST http://localhost:${PORT}/balance`);
127
+ console.log(` POST http://localhost:${PORT}/burn`);
128
+ console.log(` POST http://localhost:${PORT}/reset`);
129
+ console.log('');
130
+ console.log(' Reset a workspace balance:');
131
+ console.log(` curl -X POST http://localhost:${PORT}/reset \\`);
132
+ console.log(` -H "Content-Type: application/json" \\`);
133
+ console.log(` -d '{"workspaceId":"xxx","balance":-1}'`);
134
+ console.log('═══════════════════════════════════════════');
135
+ console.log('');
136
+ });
@@ -1,42 +0,0 @@
1
- /**
2
- * Discussion Lock Registry
3
- *
4
- * Prevents multiple bots from responding to the same discussion.
5
- * When a specialist bot (like Giuseppe) is handling a discussion,
6
- * it acquires a lock. Other bots (like Orchestrator) check the lock
7
- * before responding.
8
- */
9
- /**
10
- * Acquire a lock on a discussion
11
- * @param discussionId - The discussion to lock
12
- * @param botName - Name of the bot acquiring the lock (for logging)
13
- * @param ttlMs - Lock duration in milliseconds (default: 5 minutes)
14
- * @returns true if lock acquired, false if already locked by another bot
15
- */
16
- export declare function acquireDiscussionLock(discussionId: string, botName: string, ttlMs?: number): boolean;
17
- /**
18
- * Release a lock on a discussion
19
- * @param discussionId - The discussion to unlock
20
- * @param botName - Name of the bot releasing (must match acquirer)
21
- */
22
- export declare function releaseDiscussionLock(discussionId: string, botName: string): void;
23
- /**
24
- * Check if a discussion is locked by another bot
25
- * @param discussionId - The discussion to check
26
- * @param myBotName - Name of the checking bot (own locks don't block)
27
- * @returns true if locked by ANOTHER bot, false if free or own lock
28
- */
29
- export declare function isDiscussionLocked(discussionId: string, myBotName: string): boolean;
30
- /**
31
- * Clean up expired locks (call periodically)
32
- */
33
- export declare function cleanupExpiredLocks(): number;
34
- /**
35
- * Get current lock status (for debugging)
36
- */
37
- export declare function getLockStatus(): Map<string, {
38
- botName: string;
39
- acquiredAt: number;
40
- expiresAt: number;
41
- }>;
42
- //# sourceMappingURL=discussion-lock.d.ts.map
@@ -1,110 +0,0 @@
1
- "use strict";
2
- /**
3
- * Discussion Lock Registry
4
- *
5
- * Prevents multiple bots from responding to the same discussion.
6
- * When a specialist bot (like Giuseppe) is handling a discussion,
7
- * it acquires a lock. Other bots (like Orchestrator) check the lock
8
- * before responding.
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.acquireDiscussionLock = acquireDiscussionLock;
12
- exports.releaseDiscussionLock = releaseDiscussionLock;
13
- exports.isDiscussionLocked = isDiscussionLocked;
14
- exports.cleanupExpiredLocks = cleanupExpiredLocks;
15
- exports.getLockStatus = getLockStatus;
16
- const logger_1 = require("./logger");
17
- const logger = (0, logger_1.createLogger)({ component: 'discussion-lock' });
18
- // Singleton map of discussionId -> { botName, acquiredAt, expiresAt }
19
- const locks = new Map();
20
- // Default lock TTL: 5 minutes (allows for LLM processing time)
21
- const DEFAULT_LOCK_TTL_MS = 5 * 60 * 1000;
22
- /**
23
- * Acquire a lock on a discussion
24
- * @param discussionId - The discussion to lock
25
- * @param botName - Name of the bot acquiring the lock (for logging)
26
- * @param ttlMs - Lock duration in milliseconds (default: 5 minutes)
27
- * @returns true if lock acquired, false if already locked by another bot
28
- */
29
- function acquireDiscussionLock(discussionId, botName, ttlMs = DEFAULT_LOCK_TTL_MS) {
30
- const now = Date.now();
31
- const existing = locks.get(discussionId);
32
- // Check if existing lock is still valid
33
- if (existing && existing.expiresAt > now) {
34
- if (existing.botName === botName) {
35
- // Same bot - extend the lock
36
- existing.expiresAt = now + ttlMs;
37
- return true;
38
- }
39
- // Different bot has the lock
40
- logger.debug('Discussion already locked', {
41
- discussionId,
42
- lockedBy: existing.botName,
43
- requestedBy: botName
44
- });
45
- return false;
46
- }
47
- // Acquire lock
48
- locks.set(discussionId, {
49
- botName,
50
- acquiredAt: now,
51
- expiresAt: now + ttlMs
52
- });
53
- logger.debug('Discussion lock acquired', { discussionId, botName, ttlMs });
54
- return true;
55
- }
56
- /**
57
- * Release a lock on a discussion
58
- * @param discussionId - The discussion to unlock
59
- * @param botName - Name of the bot releasing (must match acquirer)
60
- */
61
- function releaseDiscussionLock(discussionId, botName) {
62
- const existing = locks.get(discussionId);
63
- if (existing && existing.botName === botName) {
64
- locks.delete(discussionId);
65
- logger.debug('Discussion lock released', { discussionId, botName });
66
- }
67
- }
68
- /**
69
- * Check if a discussion is locked by another bot
70
- * @param discussionId - The discussion to check
71
- * @param myBotName - Name of the checking bot (own locks don't block)
72
- * @returns true if locked by ANOTHER bot, false if free or own lock
73
- */
74
- function isDiscussionLocked(discussionId, myBotName) {
75
- const now = Date.now();
76
- const existing = locks.get(discussionId);
77
- // No lock or expired
78
- if (!existing || existing.expiresAt <= now) {
79
- return false;
80
- }
81
- // Own lock doesn't block
82
- if (existing.botName === myBotName) {
83
- return false;
84
- }
85
- return true;
86
- }
87
- /**
88
- * Clean up expired locks (call periodically)
89
- */
90
- function cleanupExpiredLocks() {
91
- const now = Date.now();
92
- let cleaned = 0;
93
- for (const [discussionId, lock] of locks.entries()) {
94
- if (lock.expiresAt <= now) {
95
- locks.delete(discussionId);
96
- cleaned++;
97
- }
98
- }
99
- if (cleaned > 0) {
100
- logger.debug('Cleaned up expired locks', { count: cleaned });
101
- }
102
- return cleaned;
103
- }
104
- /**
105
- * Get current lock status (for debugging)
106
- */
107
- function getLockStatus() {
108
- return new Map(locks);
109
- }
110
- //# sourceMappingURL=discussion-lock.js.map
@@ -1,23 +0,0 @@
1
- /**
2
- * Bot Configuration Constants
3
- */
4
- import type { BotInfo } from './types';
5
- export declare const LOCAL_STATE_FILE: string;
6
- export declare const SCHEMAS_DIR: string;
7
- export declare const LOCAL_CREDENTIALS_FILE: string;
8
- export declare const SIGNAL_DEDUP_WINDOW_MS = 5000;
9
- export declare const RESTART_DEBOUNCE_MS = 500;
10
- export declare const AGENT_DIRECTORY_PATTERNS: string[];
11
- export declare const DEPLOYED_PHASE_PATTERNS: string[];
12
- export declare const RETIRED_PHASE_PATTERNS: string[];
13
- export declare const FIELD_KEY_HAILER_PROFILE: string[];
14
- export declare const FIELD_KEY_EMAIL: string[];
15
- export declare const FIELD_KEY_PASSWORD: string[];
16
- export declare const FIELD_KEY_BOT_TYPE: string[];
17
- export declare const FIELD_KEY_SCHEMA_CONFIG: string[];
18
- export declare const LEGACY_AGENT_ACTIVITY_IDS: Record<string, string>;
19
- /**
20
- * Available bots - single source of truth
21
- */
22
- export declare const AVAILABLE_BOTS: BotInfo[];
23
- //# sourceMappingURL=constants.d.ts.map
@@ -1,94 +0,0 @@
1
- "use strict";
2
- /**
3
- * Bot Configuration Constants
4
- */
5
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- var desc = Object.getOwnPropertyDescriptor(m, k);
8
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
- desc = { enumerable: true, get: function() { return m[k]; } };
10
- }
11
- Object.defineProperty(o, k2, desc);
12
- }) : (function(o, m, k, k2) {
13
- if (k2 === undefined) k2 = k;
14
- o[k2] = m[k];
15
- }));
16
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
- Object.defineProperty(o, "default", { enumerable: true, value: v });
18
- }) : function(o, v) {
19
- o["default"] = v;
20
- });
21
- var __importStar = (this && this.__importStar) || (function () {
22
- var ownKeys = function(o) {
23
- ownKeys = Object.getOwnPropertyNames || function (o) {
24
- var ar = [];
25
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
- return ar;
27
- };
28
- return ownKeys(o);
29
- };
30
- return function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- })();
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.AVAILABLE_BOTS = exports.LEGACY_AGENT_ACTIVITY_IDS = exports.FIELD_KEY_SCHEMA_CONFIG = exports.FIELD_KEY_BOT_TYPE = exports.FIELD_KEY_PASSWORD = exports.FIELD_KEY_EMAIL = exports.FIELD_KEY_HAILER_PROFILE = exports.RETIRED_PHASE_PATTERNS = exports.DEPLOYED_PHASE_PATTERNS = exports.AGENT_DIRECTORY_PATTERNS = exports.RESTART_DEBOUNCE_MS = exports.SIGNAL_DEDUP_WINDOW_MS = exports.LOCAL_CREDENTIALS_FILE = exports.SCHEMAS_DIR = exports.LOCAL_STATE_FILE = void 0;
40
- const path = __importStar(require("path"));
41
- // File paths
42
- exports.LOCAL_STATE_FILE = path.join(process.cwd(), '.bot-state.json');
43
- exports.SCHEMAS_DIR = path.join(process.cwd(), '.bot-schemas');
44
- exports.LOCAL_CREDENTIALS_FILE = path.join(process.cwd(), '.bot-credentials.json');
45
- // Signal deduplication
46
- exports.SIGNAL_DEDUP_WINDOW_MS = 5000;
47
- exports.RESTART_DEBOUNCE_MS = 500;
48
- // Schema discovery patterns
49
- exports.AGENT_DIRECTORY_PATTERNS = ['Agent Directory', 'AI Agents', '🤖 Agent Directory'];
50
- exports.DEPLOYED_PHASE_PATTERNS = ['deployed', 'active', 'enabled'];
51
- exports.RETIRED_PHASE_PATTERNS = ['retired', 'disabled', 'inactive'];
52
- // Field key patterns for discovery
53
- exports.FIELD_KEY_HAILER_PROFILE = ['hailerProfile', 'Agent Hailer profile'];
54
- exports.FIELD_KEY_EMAIL = ['agentEmailInHailer', 'email', 'Email of Hailer profile'];
55
- exports.FIELD_KEY_PASSWORD = ['password'];
56
- exports.FIELD_KEY_BOT_TYPE = ['botType', 'bot_type', 'type'];
57
- exports.FIELD_KEY_SCHEMA_CONFIG = ['schemaConfig', 'schema_config', 'schema_config_f3a'];
58
- // Legacy activity IDs (fallback when discovery fails)
59
- exports.LEGACY_AGENT_ACTIVITY_IDS = {
60
- hal: '695e42deca61319424bc8b1f',
61
- hailerExpert: '695e42deca61319424bc8b20',
62
- bugFixer: '695e42deca61319424bc8b23',
63
- vastuullisuus: '695e42dfca61319424bc8b2e'
64
- };
65
- /**
66
- * Available bots - single source of truth
67
- */
68
- exports.AVAILABLE_BOTS = [
69
- {
70
- id: 'hal',
71
- name: 'HAL',
72
- description: 'Main orchestrator - handles general chat and coordinates specialists',
73
- icon: '🤖'
74
- },
75
- {
76
- id: 'bugFixer',
77
- name: 'Bug Fixer',
78
- description: 'Bug fixing specialist - analyzes and repairs Hailer app issues',
79
- icon: '🔧'
80
- },
81
- {
82
- id: 'hailerExpert',
83
- name: 'Hailer Expert',
84
- description: 'Workflow & data specialist - bulk operations, insights, reports',
85
- icon: '📊'
86
- },
87
- {
88
- id: 'vastuullisuus',
89
- name: 'Vastuullisuus',
90
- description: 'Sustainability analysis for SMEs',
91
- icon: '🌱'
92
- }
93
- ];
94
- //# sourceMappingURL=constants.js.map
@@ -1,253 +0,0 @@
1
- /**
2
- * Bot Configuration MCP Tools
3
- *
4
- * Manages which bots are enabled/disabled in the workspace.
5
- * Config is stored in the Agent Directory workflow - agents are activities.
6
- * - Deployed agents phase = enabled
7
- * - Retired agents phase = disabled
8
- *
9
- * Architecture (User ID-based discovery):
10
- * - In-memory state is primary (for speed), keyed by USER ID
11
- * - Agent Directory workflow is persistence layer (agents as activities, phases for state)
12
- * - On startup: Load config from Hailer by extracting hailerProfile (user ID) from each agent
13
- * - On change: Move agent activity between phases
14
- * - Credentials: Auto-synced from Hailer to local storage on discovery
15
- * - Orchestrator: Simply the first deployed bot with credentials (no special field needed)
16
- */
17
- import { z } from 'zod';
18
- import { Tool } from '../../tool-registry';
19
- import { HailerApiClient } from '../../utils/index';
20
- interface SchemaConfig {
21
- agentDirectoryWorkflowId: string | null;
22
- deployedPhaseId: string | null;
23
- retiredPhaseId: string | null;
24
- hailerProfileFieldId: string | null;
25
- emailFieldId: string | null;
26
- passwordFieldId: string | null;
27
- botTypeFieldId: string | null;
28
- }
29
- /**
30
- * Get workspace ID by Agent Directory workflow ID (reverse lookup)
31
- */
32
- export declare function getWorkspaceByWorkflowId(workflowId: string): string | null;
33
- /**
34
- * Get all configured workspace IDs
35
- */
36
- export declare function getAllConfiguredWorkspaces(): string[];
37
- /**
38
- * Set the active workspace ID (called when switching workspaces)
39
- */
40
- export declare function setActiveWorkspace(workspaceId: string): void;
41
- /**
42
- * Get the active workspace ID
43
- */
44
- export declare function getActiveWorkspace(): string | null;
45
- /**
46
- * Get schema for a workspace
47
- */
48
- export declare function getWorkspaceSchema(workspaceId: string): SchemaConfig | null;
49
- /**
50
- * Set schema for a workspace
51
- */
52
- export declare function setWorkspaceSchema(workspaceId: string, schema: SchemaConfig): void;
53
- /**
54
- * Get discovered workflow ID for a workspace (or active workspace if not specified)
55
- */
56
- export declare function getAgentDirectoryWorkflowId(workspaceId?: string): string | null;
57
- /**
58
- * Get discovered phase IDs for a workspace (or active workspace if not specified)
59
- */
60
- export declare function getPhaseIds(workspaceId?: string): {
61
- deployed: string | null;
62
- retired: string | null;
63
- };
64
- /**
65
- * Available bots - single source of truth
66
- *
67
- * All bots that can be enabled/disabled in the workspace.
68
- * This list should match the AI Hub app and agent definitions.
69
- */
70
- export declare const AVAILABLE_BOTS: {
71
- id: string;
72
- name: string;
73
- description: string;
74
- icon: string;
75
- }[];
76
- /**
77
- * Get the orchestrator user ID
78
- * Returns the user ID of the bot marked as orchestrator in Agent Directory
79
- */
80
- export declare function getOrchestratorUserId(): string | null;
81
- /**
82
- * Set the orchestrator user ID
83
- * Called during Agent Directory sync - set to first deployed bot with credentials
84
- */
85
- export declare function setOrchestratorUserId(userId: string | null): void;
86
- export declare function onBotStateChange(callback: (botId: string, enabled: boolean) => void): void;
87
- export declare function onBotCredentialsChange(callback: (botId: string) => void): void;
88
- export declare function onDaemonRestartNeeded(callback: () => void): void;
89
- /**
90
- * Cleanup function to clear pending timers and state on shutdown
91
- * Should be called from Core.stop() to prevent orphaned callbacks
92
- */
93
- export declare function cleanupBotConfig(): void;
94
- export declare function getBotState(): Record<string, boolean>;
95
- /**
96
- * Get the user ID associated with a bot
97
- */
98
- export declare function getBotUserId(botId: string): string | null;
99
- /**
100
- * Get the bot type for a user ID
101
- * Returns values like 'orchestrator', 'workflow-expert', 'bug-fixer', etc.
102
- */
103
- export declare function getBotType(userId: string): string | null;
104
- /**
105
- * Get all enabled bots with their types
106
- * Returns map of userId -> botType for enabled bots only
107
- */
108
- export declare function getEnabledBotsWithTypes(): Map<string, string | null>;
109
- /**
110
- * Set the user ID associated with a bot
111
- */
112
- export declare function setBotUserId(botId: string, userId: string | null): void;
113
- /**
114
- * Set bot enabled state
115
- *
116
- * Updates in-memory state and persists to Agent Directory by moving
117
- * the agent activity to the appropriate phase (deployed/retired).
118
- */
119
- export declare function setBotEnabled(botId: string, enabled: boolean): void;
120
- /**
121
- * Handle activity phase change signal from Hailer
122
- *
123
- * Called by signal-handler when an activity.updated signal is received.
124
- * Updates bot state if the activity belongs to Agent Directory workflow.
125
- *
126
- * NEW: Now looks up activities by user ID instead of bot type.
127
- *
128
- * @param processId - Workflow ID from the signal
129
- * @param activityIds - Array of activity IDs that were updated
130
- * @param newPhaseId - The phase the activities moved to
131
- */
132
- export declare function handleActivityPhaseChange(processId: string, activityIds: string[], newPhaseId: string): Promise<void>;
133
- /**
134
- * Force reload bot config from Hailer
135
- *
136
- * Can be called to manually refresh state from Hailer.
137
- * NEW: Now works with user IDs instead of bot IDs.
138
- *
139
- * Also handles hot-reload: if schema discovery hasn't succeeded yet
140
- * (e.g., AI Hub template wasn't installed at startup), it will
141
- * retry discovery and initialize the daemon.
142
- */
143
- export declare function reloadConfigFromHailer(): Promise<void>;
144
- /**
145
- * Initialize persistence layer
146
- * Called once during MCP server startup
147
- *
148
- * Loads bot config from local files only (no Hailer API calls on startup).
149
- * Real-time updates from Hailer are handled via signal handler when activities change.
150
- *
151
- * @param client - HailerApiClient instance for API calls
152
- */
153
- /**
154
- * Set the target workspace ID for bot config operations
155
- * Called by signal handler when workspace is switched
156
- */
157
- export declare function initBotConfigPersistence(client: HailerApiClient): Promise<void>;
158
- /**
159
- * Initialize workspace schema for a specific workspace
160
- * Called by bot clients after connecting to discover the Agent Directory in that workspace
161
- * @param client - HailerApiClient for API calls
162
- * @param workspaceId - The workspace ID to initialize schema for
163
- */
164
- export declare function initWorkspaceSchema(client: HailerApiClient, workspaceId: string): Promise<boolean>;
165
- /**
166
- * Check if persistence is initialized
167
- */
168
- export declare function isPersistenceInitialized(): boolean;
169
- /**
170
- * Bot credentials interface
171
- */
172
- export interface BotCredentials {
173
- email?: string;
174
- password?: string;
175
- }
176
- /**
177
- * Get bot credentials from Agent Directory
178
- *
179
- * Reads the email and password fields from the bot's activity.
180
- * Password is masked for security unless showPassword is true.
181
- * Falls back to local file storage if Hailer is unavailable.
182
- *
183
- * @param botIdOrActivityId - The bot ID (hal, bugFixer, etc.) or activity ID
184
- * @param showPassword - If true, returns unmasked password. Default false for security.
185
- * @returns Credentials or null if not found
186
- */
187
- export declare function getBotCredentials(botIdOrActivityId: string, showPassword?: boolean): Promise<BotCredentials | null>;
188
- /**
189
- * Update bot credentials in Agent Directory
190
- *
191
- * Writes the email and/or password to the bot's activity fields.
192
- * Only updates fields that are provided.
193
- * Saves to local file storage as backup (and uses as fallback if Hailer unavailable).
194
- *
195
- * @param botIdOrActivityId - The bot ID (hal, bugFixer, etc.) or raw activity ID
196
- * @param credentials - Credentials to update (email and/or password)
197
- */
198
- export declare function updateBotCredentials(botIdOrActivityId: string, credentials: BotCredentials): Promise<void>;
199
- /**
200
- * Get unmasked bot credentials for daemon creation
201
- *
202
- * NEW: Now primarily looks up by user ID instead of bot ID.
203
- * This function returns the actual password (not masked) from local storage.
204
- * Should only be used internally for creating bot daemon instances.
205
- *
206
- * @param userIdOrBotId - The user ID or legacy bot ID (hal, bugFixer, etc.)
207
- * @returns Unmasked credentials or null if not found
208
- */
209
- export declare function getLocalBotCredentials(userIdOrBotId: string): {
210
- email: string;
211
- password: string;
212
- displayName?: string;
213
- } | null;
214
- /**
215
- * Get all local bot credentials (for daemon initialization)
216
- * Returns all bots stored in .bot-credentials.json
217
- */
218
- export declare function getAllLocalBotCredentials(): Record<string, {
219
- email: string;
220
- password: string;
221
- displayName?: string;
222
- }>;
223
- /**
224
- * Get persistence status info (for debugging)
225
- */
226
- export declare function getPersistenceStatus(): {
227
- initialized: boolean;
228
- workflowId: string | null;
229
- deployedPhaseId: string | null;
230
- retiredPhaseId: string | null;
231
- agentActivityIds: Record<string, string>;
232
- hasClient: boolean;
233
- };
234
- /**
235
- * List available bots and their status
236
- */
237
- export declare const listBotsConfigTool: Tool;
238
- /**
239
- * Enable a bot
240
- */
241
- export declare const enableBotTool: Tool;
242
- /**
243
- * Disable a bot
244
- */
245
- export declare const disableBotTool: Tool;
246
- /**
247
- * Check specialist status from Agent Directory
248
- * Returns real-time status showing which specialists are deployed vs retired
249
- */
250
- export declare const checkSpecialistStatusTool: Tool;
251
- export declare const botConfigTools: Tool<z.ZodType<any, z.ZodTypeDef, any>>[];
252
- export {};
253
- //# sourceMappingURL=core.d.ts.map