@hailer/mcp 0.1.14 → 0.1.16

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 (112) hide show
  1. package/.claude/agents/agent-giuseppe-app-builder.md +7 -6
  2. package/.claude/agents/agent-lars-code-inspector.md +26 -14
  3. package/dist/agents/bot-manager.d.ts +48 -0
  4. package/dist/agents/bot-manager.js +254 -0
  5. package/dist/agents/factory.d.ts +150 -0
  6. package/dist/agents/factory.js +650 -0
  7. package/dist/agents/giuseppe/ai.d.ts +83 -0
  8. package/dist/agents/giuseppe/ai.js +466 -0
  9. package/dist/agents/giuseppe/bot.d.ts +110 -0
  10. package/dist/agents/giuseppe/bot.js +780 -0
  11. package/dist/agents/giuseppe/config.d.ts +25 -0
  12. package/dist/agents/giuseppe/config.js +227 -0
  13. package/dist/agents/giuseppe/files.d.ts +52 -0
  14. package/dist/agents/giuseppe/files.js +338 -0
  15. package/dist/agents/giuseppe/git.d.ts +48 -0
  16. package/dist/agents/giuseppe/git.js +298 -0
  17. package/dist/agents/giuseppe/index.d.ts +97 -0
  18. package/dist/agents/giuseppe/index.js +258 -0
  19. package/dist/agents/giuseppe/lsp.d.ts +113 -0
  20. package/dist/agents/giuseppe/lsp.js +485 -0
  21. package/dist/agents/giuseppe/monitor.d.ts +118 -0
  22. package/dist/agents/giuseppe/monitor.js +621 -0
  23. package/dist/agents/giuseppe/prompt.d.ts +5 -0
  24. package/dist/agents/giuseppe/prompt.js +94 -0
  25. package/dist/agents/giuseppe/registries/pending-classification.d.ts +28 -0
  26. package/dist/agents/giuseppe/registries/pending-classification.js +50 -0
  27. package/dist/agents/giuseppe/registries/pending-fix.d.ts +30 -0
  28. package/dist/agents/giuseppe/registries/pending-fix.js +42 -0
  29. package/dist/agents/giuseppe/registries/pending.d.ts +27 -0
  30. package/dist/agents/giuseppe/registries/pending.js +49 -0
  31. package/dist/agents/giuseppe/specialist.d.ts +47 -0
  32. package/dist/agents/giuseppe/specialist.js +237 -0
  33. package/dist/agents/giuseppe/types.d.ts +123 -0
  34. package/dist/agents/giuseppe/types.js +9 -0
  35. package/dist/agents/hailer-expert/index.d.ts +8 -0
  36. package/dist/agents/hailer-expert/index.js +14 -0
  37. package/dist/agents/hal/daemon.d.ts +142 -0
  38. package/dist/agents/hal/daemon.js +1103 -0
  39. package/dist/agents/hal/definitions.d.ts +55 -0
  40. package/dist/agents/hal/definitions.js +263 -0
  41. package/dist/agents/hal/index.d.ts +3 -0
  42. package/dist/agents/hal/index.js +8 -0
  43. package/dist/agents/index.d.ts +18 -0
  44. package/dist/agents/index.js +48 -0
  45. package/dist/agents/shared/base.d.ts +216 -0
  46. package/dist/agents/shared/base.js +846 -0
  47. package/dist/agents/shared/services/agent-registry.d.ts +107 -0
  48. package/dist/agents/shared/services/agent-registry.js +629 -0
  49. package/dist/agents/shared/services/conversation-manager.d.ts +50 -0
  50. package/dist/agents/shared/services/conversation-manager.js +136 -0
  51. package/dist/agents/shared/services/mcp-client.d.ts +56 -0
  52. package/dist/agents/shared/services/mcp-client.js +124 -0
  53. package/dist/agents/shared/services/message-classifier.d.ts +37 -0
  54. package/dist/agents/shared/services/message-classifier.js +187 -0
  55. package/dist/agents/shared/services/message-formatter.d.ts +89 -0
  56. package/dist/agents/shared/services/message-formatter.js +371 -0
  57. package/dist/agents/shared/services/session-logger.d.ts +106 -0
  58. package/dist/agents/shared/services/session-logger.js +446 -0
  59. package/dist/agents/shared/services/tool-executor.d.ts +41 -0
  60. package/dist/agents/shared/services/tool-executor.js +169 -0
  61. package/dist/agents/shared/services/workspace-schema-cache.d.ts +125 -0
  62. package/dist/agents/shared/services/workspace-schema-cache.js +578 -0
  63. package/dist/agents/shared/specialist.d.ts +91 -0
  64. package/dist/agents/shared/specialist.js +399 -0
  65. package/dist/agents/shared/tool-schema-loader.d.ts +62 -0
  66. package/dist/agents/shared/tool-schema-loader.js +232 -0
  67. package/dist/agents/shared/types.d.ts +327 -0
  68. package/dist/agents/shared/types.js +121 -0
  69. package/dist/app.js +21 -4
  70. package/dist/cli.js +0 -0
  71. package/dist/client/agents/orchestrator.d.ts +1 -0
  72. package/dist/client/agents/orchestrator.js +12 -1
  73. package/dist/commands/seed-config.d.ts +9 -0
  74. package/dist/commands/seed-config.js +372 -0
  75. package/dist/config.d.ts +10 -0
  76. package/dist/config.js +61 -1
  77. package/dist/core.d.ts +8 -0
  78. package/dist/core.js +137 -6
  79. package/dist/lib/discussion-lock.d.ts +42 -0
  80. package/dist/lib/discussion-lock.js +110 -0
  81. package/dist/mcp/UserContextCache.js +2 -2
  82. package/dist/mcp/hailer-clients.d.ts +15 -0
  83. package/dist/mcp/hailer-clients.js +100 -6
  84. package/dist/mcp/signal-handler.d.ts +16 -5
  85. package/dist/mcp/signal-handler.js +173 -122
  86. package/dist/mcp/tools/activity.js +9 -1
  87. package/dist/mcp/tools/bot-config.d.ts +184 -9
  88. package/dist/mcp/tools/bot-config.js +2177 -163
  89. package/dist/mcp/tools/giuseppe-tools.d.ts +21 -0
  90. package/dist/mcp/tools/giuseppe-tools.js +525 -0
  91. package/dist/mcp/utils/hailer-api-client.d.ts +42 -1
  92. package/dist/mcp/utils/hailer-api-client.js +128 -2
  93. package/dist/mcp/webhook-handler.d.ts +87 -0
  94. package/dist/mcp/webhook-handler.js +343 -0
  95. package/dist/mcp/workspace-cache.d.ts +5 -0
  96. package/dist/mcp/workspace-cache.js +11 -0
  97. package/dist/mcp-server.js +55 -5
  98. package/dist/modules/bug-reports/giuseppe-agent.d.ts +58 -0
  99. package/dist/modules/bug-reports/giuseppe-agent.js +467 -0
  100. package/dist/modules/bug-reports/giuseppe-ai.d.ts +25 -1
  101. package/dist/modules/bug-reports/giuseppe-ai.js +133 -2
  102. package/dist/modules/bug-reports/giuseppe-bot.d.ts +3 -2
  103. package/dist/modules/bug-reports/giuseppe-bot.js +75 -36
  104. package/dist/modules/bug-reports/giuseppe-daemon.d.ts +80 -0
  105. package/dist/modules/bug-reports/giuseppe-daemon.js +617 -0
  106. package/dist/modules/bug-reports/giuseppe-files.d.ts +12 -0
  107. package/dist/modules/bug-reports/giuseppe-files.js +37 -0
  108. package/dist/modules/bug-reports/giuseppe-lsp.d.ts +113 -0
  109. package/dist/modules/bug-reports/giuseppe-lsp.js +485 -0
  110. package/dist/modules/bug-reports/index.d.ts +1 -0
  111. package/dist/modules/bug-reports/index.js +31 -29
  112. package/package.json +5 -4
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Workspace Schema Cache Service
3
+ *
4
+ * Dynamically discovers and caches workflow schemas per workspace.
5
+ * Replaces hardcoded workflow/field IDs with runtime lookup.
6
+ *
7
+ * WORKSPACE ISOLATION: Each workspace gets its own workflow IDs.
8
+ * Never use hardcoded IDs - always lookup via this cache.
9
+ *
10
+ * On bot startup:
11
+ * 1. Check memory cache first
12
+ * 2. If cache miss: Query list_workflows to find AI Agent workflows by name
13
+ * 3. If missing, install them from marketplace
14
+ * 4. Query get_workflow_schema to get field IDs
15
+ * 5. Store in memory cache for session duration
16
+ */
17
+ import { Logger } from "../../../lib/logger";
18
+ import { McpToolCallback } from "../../shared/types";
19
+ /** Cached workflow schema */
20
+ export interface WorkflowSchema {
21
+ workflowId: string;
22
+ name: string;
23
+ phases: Record<string, string>;
24
+ fields: Record<string, string>;
25
+ }
26
+ /** Per-workspace cache */
27
+ export interface WorkspaceSchemas {
28
+ workspaceId: string;
29
+ sessionLog?: WorkflowSchema;
30
+ agentDirectory?: WorkflowSchema;
31
+ positions?: WorkflowSchema;
32
+ teams?: WorkflowSchema;
33
+ toolRegistry?: WorkflowSchema;
34
+ mcpConfig?: WorkflowSchema;
35
+ initialized: boolean;
36
+ }
37
+ export declare class WorkspaceSchemaCacheService {
38
+ private logger;
39
+ private callMcpTool;
40
+ private cache;
41
+ constructor(logger: Logger, callMcpTool: McpToolCallback);
42
+ /**
43
+ * Initialize schema cache for a workspace
44
+ * Call this on bot startup after connecting to Hailer
45
+ */
46
+ initializeForWorkspace(workspaceId: string): Promise<WorkspaceSchemas>;
47
+ /**
48
+ * Get cached schemas for a workspace
49
+ */
50
+ getSchemas(workspaceId: string): WorkspaceSchemas | undefined;
51
+ /**
52
+ * Get Session Log schema for a workspace
53
+ */
54
+ getSessionLogSchema(workspaceId: string): WorkflowSchema | undefined;
55
+ /**
56
+ * Get Agent Directory schema for a workspace
57
+ */
58
+ getAgentDirectorySchema(workspaceId: string): WorkflowSchema | undefined;
59
+ /**
60
+ * Get Positions schema for a workspace
61
+ */
62
+ getPositionsSchema(workspaceId: string): WorkflowSchema | undefined;
63
+ /**
64
+ * Get Teams schema for a workspace
65
+ */
66
+ getTeamsSchema(workspaceId: string): WorkflowSchema | undefined;
67
+ /**
68
+ * Get Tool Registry schema for a workspace
69
+ */
70
+ getToolRegistrySchema(workspaceId: string): WorkflowSchema | undefined;
71
+ /**
72
+ * Get MCP Config schema for a workspace
73
+ */
74
+ getMcpConfigSchema(workspaceId: string): WorkflowSchema | undefined;
75
+ /**
76
+ * Check if a workspace has the AI Agent template installed
77
+ */
78
+ hasAgentTemplate(workspaceId: string): boolean;
79
+ /**
80
+ * Check if workflow name matches a pattern (case insensitive, ignores emojis)
81
+ */
82
+ private matchesPattern;
83
+ /**
84
+ * Map workflow list to schema slots (using pattern matching)
85
+ */
86
+ private mapWorkflowsToSchemas;
87
+ /**
88
+ * Load detailed schemas (phases, fields) for all found workflows
89
+ */
90
+ private loadDetailedSchemas;
91
+ /**
92
+ * Install AI Agent template from marketplace
93
+ */
94
+ private installAgentTemplate;
95
+ /**
96
+ * Parse workflows from list_workflows response
97
+ * Handles both raw JSON and markdown-wrapped JSON responses
98
+ */
99
+ private parseWorkflows;
100
+ /**
101
+ * Load detailed workflow schema (phases and fields) for an existing schema
102
+ */
103
+ private loadWorkflowSchemaDetails;
104
+ /**
105
+ * Parse phases from list_workflow_phases response
106
+ * Format: 1. **PhaseName**\n - Phase ID: `phaseId`
107
+ */
108
+ private parsePhases;
109
+ /**
110
+ * Parse fields from get_workflow_schema response
111
+ * Stores fields by both label and key for flexible lookup
112
+ */
113
+ private parseFields;
114
+ /**
115
+ * Map field keys to their IDs in the schema
116
+ * Since parseFields now stores by key directly, this is a no-op
117
+ * Kept for backwards compatibility but does nothing
118
+ */
119
+ private mapFieldLabelsToIds;
120
+ /**
121
+ * Clear cache for a workspace (memory cache only)
122
+ */
123
+ clearCache(workspaceId?: string): void;
124
+ }
125
+ //# sourceMappingURL=workspace-schema-cache.d.ts.map
@@ -0,0 +1,578 @@
1
+ "use strict";
2
+ /**
3
+ * Workspace Schema Cache Service
4
+ *
5
+ * Dynamically discovers and caches workflow schemas per workspace.
6
+ * Replaces hardcoded workflow/field IDs with runtime lookup.
7
+ *
8
+ * WORKSPACE ISOLATION: Each workspace gets its own workflow IDs.
9
+ * Never use hardcoded IDs - always lookup via this cache.
10
+ *
11
+ * On bot startup:
12
+ * 1. Check memory cache first
13
+ * 2. If cache miss: Query list_workflows to find AI Agent workflows by name
14
+ * 3. If missing, install them from marketplace
15
+ * 4. Query get_workflow_schema to get field IDs
16
+ * 5. Store in memory cache for session duration
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.WorkspaceSchemaCacheService = void 0;
20
+ /** AI Agent template ID in marketplace (HR for AI Agents) */
21
+ const AI_AGENT_TEMPLATE_ID = "685ab3c39af7445dd5384ffd";
22
+ /** Known workflow names from the AI Agent template (partial match, case insensitive) */
23
+ const TEMPLATE_WORKFLOW_PATTERNS = {
24
+ SESSION_LOG: ["session log", "session_log"],
25
+ AGENT_DIRECTORY: ["agent directory", "agent_directory"],
26
+ POSITIONS: ["positions", "position"],
27
+ TEAMS: ["teams", "team"],
28
+ TOOL_REGISTRY: ["tool registry", "tool_registry", "mcp server"],
29
+ MCP_CONFIG: ["mcp config", "mcp_config", "mcp configuration"],
30
+ };
31
+ /** Known field labels we need to look up */
32
+ const SESSION_LOG_FIELD_LABELS = {
33
+ contextSummary: "Context summary",
34
+ previousLog: "Previus log entry", // Note: typo in original template
35
+ linkedWork: "Most relevant link to work",
36
+ cost: "Tokens Used",
37
+ madeBy: "Log entry made by",
38
+ };
39
+ const AGENT_DIRECTORY_FIELD_LABELS = {
40
+ firstName: "First name",
41
+ lastName: "Last name",
42
+ description: "Description",
43
+ email: "Email",
44
+ password: "Password",
45
+ hailerProfile: "Hailer profile",
46
+ team: "Team",
47
+ supervisor: "Supervisor",
48
+ memory: "Memory",
49
+ position: "Position",
50
+ startDate: "Start date",
51
+ };
52
+ const POSITIONS_FIELD_LABELS = {
53
+ purpose: "Purpose",
54
+ personaTone: "Persona / Tone",
55
+ coreCapabilities: "Core Capabilities",
56
+ boundaries: "Boundaries",
57
+ agentCount: "Agents in this position",
58
+ multiAllowed: "Multi allowed",
59
+ };
60
+ const TEAMS_FIELD_LABELS = {
61
+ info: "Info",
62
+ leader: "Leader",
63
+ };
64
+ const TOOL_REGISTRY_FIELD_LABELS = {
65
+ baseUrl: "Base URL",
66
+ protocolVersion: "Protocol Version",
67
+ toolRegistry: "Tool Registry",
68
+ logEntryBy: "Log entry by",
69
+ };
70
+ const MCP_CONFIG_FIELD_LABELS = {
71
+ agentName: "Agent Name",
72
+ agentId: "Agent ID",
73
+ publicKey: "Public Key",
74
+ accessTo: "Access To",
75
+ authToken: "Auth Token",
76
+ apiKey: "API Key",
77
+ workspaceId: "Workspace ID",
78
+ permissions: "Permissions",
79
+ sessionId: "Session ID",
80
+ resourceLimits: "Resource Limits",
81
+ loggingEndpoint: "Logging Endpoint",
82
+ callbackUrl: "Callback URL",
83
+ customContext: "Custom Context",
84
+ permCreate: "Create",
85
+ permRead: "Read",
86
+ permUpdate: "Update",
87
+ permDelete: "Delete",
88
+ };
89
+ class WorkspaceSchemaCacheService {
90
+ logger;
91
+ callMcpTool;
92
+ cache = new Map();
93
+ constructor(logger, callMcpTool) {
94
+ this.logger = logger;
95
+ this.callMcpTool = callMcpTool;
96
+ }
97
+ /**
98
+ * Initialize schema cache for a workspace
99
+ * Call this on bot startup after connecting to Hailer
100
+ */
101
+ async initializeForWorkspace(workspaceId) {
102
+ // 1. Check memory cache first
103
+ const existing = this.cache.get(workspaceId);
104
+ if (existing?.initialized) {
105
+ this.logger.debug("Using memory-cached workspace schemas", { workspaceId });
106
+ return existing;
107
+ }
108
+ // 2. Discover via API
109
+ this.logger.info("Discovering workspace schemas via API", { workspaceId });
110
+ const schemas = {
111
+ workspaceId,
112
+ initialized: false,
113
+ };
114
+ try {
115
+ // Fetch all workflows in workspace
116
+ const workflowsResult = await this.callMcpTool("list_workflows", {
117
+ workspace: workspaceId,
118
+ });
119
+ const workflowsText = workflowsResult?.content?.[0]?.text;
120
+ if (!workflowsText) {
121
+ this.logger.warn("No workflows found in workspace", { workspaceId });
122
+ schemas.initialized = true;
123
+ this.cache.set(workspaceId, schemas);
124
+ return schemas;
125
+ }
126
+ // Parse workflows
127
+ const workflows = this.parseWorkflows(workflowsText);
128
+ this.logger.debug("Found workflows", { workspaceId, count: workflows.length });
129
+ // Find template workflows
130
+ this.mapWorkflowsToSchemas(workflows, schemas);
131
+ // Check if required workflows are missing
132
+ const missingRequired = !schemas.sessionLog || !schemas.agentDirectory;
133
+ if (missingRequired) {
134
+ this.logger.info("AI Agent workflows not found, installing from marketplace", { workspaceId });
135
+ const installed = await this.installAgentTemplate(workspaceId);
136
+ if (installed) {
137
+ // Re-fetch workflows after installation
138
+ const refreshResult = await this.callMcpTool("list_workflows", {
139
+ workspace: workspaceId,
140
+ });
141
+ const refreshText = refreshResult?.content?.[0]?.text;
142
+ if (refreshText) {
143
+ const refreshedWorkflows = this.parseWorkflows(refreshText);
144
+ this.mapWorkflowsToSchemas(refreshedWorkflows, schemas);
145
+ }
146
+ }
147
+ }
148
+ // Load detailed schemas for found workflows
149
+ await this.loadDetailedSchemas(schemas);
150
+ schemas.initialized = true;
151
+ this.cache.set(workspaceId, schemas);
152
+ this.logger.info("Workspace schemas cached", {
153
+ workspaceId,
154
+ hasSessionLog: !!schemas.sessionLog,
155
+ hasAgentDirectory: !!schemas.agentDirectory,
156
+ hasPositions: !!schemas.positions,
157
+ });
158
+ return schemas;
159
+ }
160
+ catch (error) {
161
+ this.logger.error("Failed to initialize workspace schemas", {
162
+ workspaceId,
163
+ error: error instanceof Error ? error.message : String(error),
164
+ });
165
+ schemas.initialized = true; // Mark as initialized even on error to prevent retry loops
166
+ this.cache.set(workspaceId, schemas);
167
+ return schemas;
168
+ }
169
+ }
170
+ /**
171
+ * Get cached schemas for a workspace
172
+ */
173
+ getSchemas(workspaceId) {
174
+ return this.cache.get(workspaceId);
175
+ }
176
+ /**
177
+ * Get Session Log schema for a workspace
178
+ */
179
+ getSessionLogSchema(workspaceId) {
180
+ return this.cache.get(workspaceId)?.sessionLog;
181
+ }
182
+ /**
183
+ * Get Agent Directory schema for a workspace
184
+ */
185
+ getAgentDirectorySchema(workspaceId) {
186
+ return this.cache.get(workspaceId)?.agentDirectory;
187
+ }
188
+ /**
189
+ * Get Positions schema for a workspace
190
+ */
191
+ getPositionsSchema(workspaceId) {
192
+ return this.cache.get(workspaceId)?.positions;
193
+ }
194
+ /**
195
+ * Get Teams schema for a workspace
196
+ */
197
+ getTeamsSchema(workspaceId) {
198
+ return this.cache.get(workspaceId)?.teams;
199
+ }
200
+ /**
201
+ * Get Tool Registry schema for a workspace
202
+ */
203
+ getToolRegistrySchema(workspaceId) {
204
+ return this.cache.get(workspaceId)?.toolRegistry;
205
+ }
206
+ /**
207
+ * Get MCP Config schema for a workspace
208
+ */
209
+ getMcpConfigSchema(workspaceId) {
210
+ return this.cache.get(workspaceId)?.mcpConfig;
211
+ }
212
+ /**
213
+ * Check if a workspace has the AI Agent template installed
214
+ */
215
+ hasAgentTemplate(workspaceId) {
216
+ const schemas = this.cache.get(workspaceId);
217
+ return !!(schemas?.sessionLog && schemas?.agentDirectory);
218
+ }
219
+ /**
220
+ * Check if workflow name matches a pattern (case insensitive, ignores emojis)
221
+ */
222
+ matchesPattern(workflowName, patterns) {
223
+ // Normalize: lowercase, remove emojis and extra whitespace
224
+ const normalized = workflowName
225
+ .toLowerCase()
226
+ .replace(/[\u{1F300}-\u{1F9FF}]/gu, "") // Remove emojis
227
+ .replace(/\s+/g, " ")
228
+ .trim();
229
+ return patterns.some(pattern => normalized.includes(pattern));
230
+ }
231
+ /**
232
+ * Map workflow list to schema slots (using pattern matching)
233
+ */
234
+ mapWorkflowsToSchemas(workflows, schemas) {
235
+ for (const workflow of workflows) {
236
+ // Filter by workspace if specified
237
+ if (schemas.workspaceId && workflow.workspaceId && workflow.workspaceId !== schemas.workspaceId) {
238
+ continue;
239
+ }
240
+ if (this.matchesPattern(workflow.name, TEMPLATE_WORKFLOW_PATTERNS.SESSION_LOG)) {
241
+ schemas.sessionLog = { workflowId: workflow.id, name: workflow.name, phases: {}, fields: {} };
242
+ }
243
+ else if (this.matchesPattern(workflow.name, TEMPLATE_WORKFLOW_PATTERNS.AGENT_DIRECTORY)) {
244
+ schemas.agentDirectory = { workflowId: workflow.id, name: workflow.name, phases: {}, fields: {} };
245
+ }
246
+ else if (this.matchesPattern(workflow.name, TEMPLATE_WORKFLOW_PATTERNS.POSITIONS)) {
247
+ schemas.positions = { workflowId: workflow.id, name: workflow.name, phases: {}, fields: {} };
248
+ }
249
+ else if (this.matchesPattern(workflow.name, TEMPLATE_WORKFLOW_PATTERNS.TEAMS) && workflow.name.toLowerCase().includes("team")) {
250
+ // Be more specific for Teams to avoid matching "Teams" workflow in sports data
251
+ if (workflow.name.includes("🎖️") || workflow.name.toLowerCase() === "teams") {
252
+ schemas.teams = { workflowId: workflow.id, name: workflow.name, phases: {}, fields: {} };
253
+ }
254
+ }
255
+ else if (this.matchesPattern(workflow.name, TEMPLATE_WORKFLOW_PATTERNS.TOOL_REGISTRY)) {
256
+ schemas.toolRegistry = { workflowId: workflow.id, name: workflow.name, phases: {}, fields: {} };
257
+ }
258
+ else if (this.matchesPattern(workflow.name, TEMPLATE_WORKFLOW_PATTERNS.MCP_CONFIG)) {
259
+ schemas.mcpConfig = { workflowId: workflow.id, name: workflow.name, phases: {}, fields: {} };
260
+ }
261
+ }
262
+ }
263
+ /**
264
+ * Load detailed schemas (phases, fields) for all found workflows
265
+ */
266
+ async loadDetailedSchemas(schemas) {
267
+ if (schemas.sessionLog) {
268
+ await this.loadWorkflowSchemaDetails(schemas.sessionLog);
269
+ this.mapFieldLabelsToIds(schemas.sessionLog, SESSION_LOG_FIELD_LABELS);
270
+ }
271
+ if (schemas.agentDirectory) {
272
+ await this.loadWorkflowSchemaDetails(schemas.agentDirectory);
273
+ this.mapFieldLabelsToIds(schemas.agentDirectory, AGENT_DIRECTORY_FIELD_LABELS);
274
+ }
275
+ if (schemas.positions) {
276
+ await this.loadWorkflowSchemaDetails(schemas.positions);
277
+ this.mapFieldLabelsToIds(schemas.positions, POSITIONS_FIELD_LABELS);
278
+ }
279
+ if (schemas.teams) {
280
+ await this.loadWorkflowSchemaDetails(schemas.teams);
281
+ this.mapFieldLabelsToIds(schemas.teams, TEAMS_FIELD_LABELS);
282
+ }
283
+ if (schemas.toolRegistry) {
284
+ await this.loadWorkflowSchemaDetails(schemas.toolRegistry);
285
+ this.mapFieldLabelsToIds(schemas.toolRegistry, TOOL_REGISTRY_FIELD_LABELS);
286
+ }
287
+ if (schemas.mcpConfig) {
288
+ await this.loadWorkflowSchemaDetails(schemas.mcpConfig);
289
+ this.mapFieldLabelsToIds(schemas.mcpConfig, MCP_CONFIG_FIELD_LABELS);
290
+ }
291
+ }
292
+ /**
293
+ * Install AI Agent template from marketplace
294
+ */
295
+ async installAgentTemplate(workspaceId) {
296
+ try {
297
+ // First try to find the template by name in marketplace
298
+ const templatesResult = await this.callMcpTool("list_templates", {
299
+ publicOnly: true,
300
+ });
301
+ let templateId = AI_AGENT_TEMPLATE_ID;
302
+ const templatesText = templatesResult?.content?.[0]?.text;
303
+ if (templatesText) {
304
+ try {
305
+ const parsed = JSON.parse(templatesText);
306
+ const templates = parsed.templates || parsed.data || parsed;
307
+ if (Array.isArray(templates)) {
308
+ const agentTemplate = templates.find((t) => t.name?.includes("AI Agent") || t.title?.includes("AI Agent"));
309
+ if (agentTemplate?._id) {
310
+ templateId = agentTemplate._id;
311
+ }
312
+ }
313
+ }
314
+ catch {
315
+ // Use default template ID
316
+ }
317
+ }
318
+ this.logger.info("Installing AI Agent template", { workspaceId, templateId });
319
+ const installResult = await this.callMcpTool("install_template", {
320
+ templateId,
321
+ workspaceId,
322
+ });
323
+ const installText = installResult?.content?.[0]?.text || "";
324
+ // Check for explicit error indicators
325
+ const hasError = installText.toLowerCase().includes("error") ||
326
+ installText.toLowerCase().includes("not found") ||
327
+ installText.toLowerCase().includes("failed");
328
+ const hasSuccess = installText.toLowerCase().includes("success") ||
329
+ installText.toLowerCase().includes("installed") ||
330
+ installText.toLowerCase().includes("created");
331
+ const success = hasSuccess && !hasError;
332
+ if (success) {
333
+ this.logger.info("AI Agent template installed successfully", { workspaceId });
334
+ }
335
+ else {
336
+ this.logger.warn("Template installation failed", {
337
+ workspaceId,
338
+ response: installText.substring(0, 300),
339
+ });
340
+ }
341
+ return success;
342
+ }
343
+ catch (error) {
344
+ this.logger.error("Failed to install AI Agent template", {
345
+ workspaceId,
346
+ error: error instanceof Error ? error.message : String(error),
347
+ });
348
+ return false;
349
+ }
350
+ }
351
+ /**
352
+ * Parse workflows from list_workflows response
353
+ * Handles both raw JSON and markdown-wrapped JSON responses
354
+ */
355
+ parseWorkflows(text) {
356
+ const workflows = [];
357
+ try {
358
+ // First, try to extract JSON array from markdown-wrapped response
359
+ // The response often has: "📋 **18 Workflows Found**\n\n[\n {...}\n]\n\n🔗 **Relationships**..."
360
+ let jsonText = text;
361
+ // Try to extract JSON array from markdown
362
+ const jsonArrayMatch = text.match(/\[\s*\{[\s\S]*?\}\s*\]/);
363
+ if (jsonArrayMatch) {
364
+ jsonText = jsonArrayMatch[0];
365
+ }
366
+ const parsed = JSON.parse(jsonText);
367
+ const items = Array.isArray(parsed) ? parsed : (parsed.workflows || parsed.data || []);
368
+ if (Array.isArray(items)) {
369
+ for (const item of items) {
370
+ // Support both `id` and `_id` field names
371
+ const id = item.id || item._id;
372
+ const name = item.name;
373
+ const workspaceId = item.workspaceId;
374
+ if (id && name) {
375
+ workflows.push({ id, name, workspaceId });
376
+ }
377
+ }
378
+ }
379
+ }
380
+ catch {
381
+ // Fallback: regex extraction for both id and _id patterns
382
+ const idMatches = text.matchAll(/"(?:id|_id)":\s*"([a-f0-9]{24})"/gi);
383
+ const nameMatches = text.matchAll(/"name":\s*"([^"]+)"/gi);
384
+ const wsMatches = text.matchAll(/"workspaceId":\s*"([a-f0-9]{24})"/gi);
385
+ const ids = [...idMatches].map(m => m[1]);
386
+ const names = [...nameMatches].map(m => m[1]);
387
+ const wsIds = [...wsMatches].map(m => m[1]);
388
+ for (let i = 0; i < Math.min(ids.length, names.length); i++) {
389
+ workflows.push({
390
+ id: ids[i],
391
+ name: names[i],
392
+ workspaceId: wsIds[i],
393
+ });
394
+ }
395
+ }
396
+ this.logger.debug("Parsed workflows from response", { count: workflows.length });
397
+ return workflows;
398
+ }
399
+ /**
400
+ * Load detailed workflow schema (phases and fields) for an existing schema
401
+ */
402
+ async loadWorkflowSchemaDetails(schema) {
403
+ try {
404
+ // Get phases first
405
+ const phasesResult = await this.callMcpTool("list_workflow_phases", {
406
+ workflowId: schema.workflowId,
407
+ });
408
+ const phasesText = phasesResult?.content?.[0]?.text;
409
+ if (phasesText) {
410
+ this.parsePhases(phasesText, schema);
411
+ }
412
+ this.logger.debug("Parsed phases for workflow", {
413
+ workflowId: schema.workflowId,
414
+ workflowName: schema.name,
415
+ phaseCount: Object.keys(schema.phases).length,
416
+ phases: Object.keys(schema.phases),
417
+ });
418
+ // Get schema with fields (use first phase)
419
+ const firstPhaseId = Object.values(schema.phases)[0];
420
+ if (firstPhaseId) {
421
+ const schemaResult = await this.callMcpTool("get_workflow_schema", {
422
+ workflowId: schema.workflowId,
423
+ phaseId: firstPhaseId,
424
+ });
425
+ const schemaText = schemaResult?.content?.[0]?.text;
426
+ if (schemaText) {
427
+ this.parseFields(schemaText, schema);
428
+ this.logger.debug("Parsed fields for workflow", {
429
+ workflowId: schema.workflowId,
430
+ workflowName: schema.name,
431
+ fieldCount: Object.keys(schema.fields).length,
432
+ fieldKeys: Object.keys(schema.fields).slice(0, 10), // First 10 keys
433
+ });
434
+ }
435
+ else {
436
+ this.logger.warn("No schema text returned from get_workflow_schema", {
437
+ workflowId: schema.workflowId,
438
+ });
439
+ }
440
+ }
441
+ else {
442
+ this.logger.warn("No phase ID found - skipping field schema load", {
443
+ workflowId: schema.workflowId,
444
+ workflowName: schema.name,
445
+ });
446
+ }
447
+ }
448
+ catch (error) {
449
+ this.logger.warn("Failed to load workflow schema details", {
450
+ workflowId: schema.workflowId,
451
+ workflowName: schema.name,
452
+ error: error instanceof Error ? error.message : String(error),
453
+ });
454
+ }
455
+ }
456
+ /**
457
+ * Parse phases from list_workflow_phases response
458
+ * Format: 1. **PhaseName**\n - Phase ID: `phaseId`
459
+ */
460
+ parsePhases(text, schema) {
461
+ this.logger.debug("Parsing phases text", {
462
+ workflowId: schema.workflowId,
463
+ textLength: text.length,
464
+ textPreview: text.substring(0, 500),
465
+ });
466
+ try {
467
+ const parsed = JSON.parse(text);
468
+ const phases = parsed.phases || parsed.data || parsed;
469
+ if (Array.isArray(phases)) {
470
+ for (const phase of phases) {
471
+ if (phase.id && phase.name) {
472
+ schema.phases[phase.name.toLowerCase()] = phase.id;
473
+ }
474
+ else if (phase._id && phase.name) {
475
+ schema.phases[phase.name.toLowerCase()] = phase._id;
476
+ }
477
+ }
478
+ }
479
+ }
480
+ catch {
481
+ // Markdown format: **PhaseName**\n - Phase ID: `phaseId`
482
+ // Match pattern: \d+\. **Name** ... Phase ID: `id`
483
+ const phaseBlocks = text.split(/\d+\.\s*\*\*/).filter(Boolean);
484
+ for (const block of phaseBlocks) {
485
+ const nameMatch = block.match(/^([^*]+)\*\*/);
486
+ const phaseIdMatch = block.match(/Phase ID:\s*`([a-f0-9]{24})`/i);
487
+ if (nameMatch && phaseIdMatch) {
488
+ const phaseName = nameMatch[1].trim();
489
+ const phaseId = phaseIdMatch[1];
490
+ schema.phases[phaseName.toLowerCase()] = phaseId;
491
+ }
492
+ }
493
+ }
494
+ }
495
+ /**
496
+ * Parse fields from get_workflow_schema response
497
+ * Stores fields by both label and key for flexible lookup
498
+ */
499
+ parseFields(text, schema) {
500
+ try {
501
+ const parsed = JSON.parse(text);
502
+ const fields = parsed.fields || parsed.data || parsed;
503
+ if (Array.isArray(fields)) {
504
+ for (const field of fields) {
505
+ const fieldId = field.id || field._id || field.fieldId;
506
+ const label = field.label || field.name;
507
+ const key = field.key;
508
+ if (fieldId && label) {
509
+ schema.fields[label] = fieldId;
510
+ }
511
+ // Also store by key for direct lookup (e.g., "firstName" -> fieldId)
512
+ if (fieldId && key) {
513
+ schema.fields[key] = fieldId;
514
+ }
515
+ }
516
+ }
517
+ else if (typeof fields === "object") {
518
+ // Handle object format {fieldId: {label, type, key, ...}}
519
+ for (const [fieldId, fieldData] of Object.entries(fields)) {
520
+ const data = fieldData;
521
+ const label = data.label || data.name;
522
+ const key = data.key;
523
+ if (label) {
524
+ schema.fields[label] = fieldId;
525
+ }
526
+ // Also store by key
527
+ if (key) {
528
+ schema.fields[key] = fieldId;
529
+ }
530
+ }
531
+ }
532
+ }
533
+ catch {
534
+ // Regex fallback for markdown format:
535
+ // **Label**
536
+ // - Field ID: `fieldId`
537
+ // - Key: `key`
538
+ const fieldBlocks = text.split(/\d+\.\s*\*\*/).filter(Boolean);
539
+ for (const block of fieldBlocks) {
540
+ const labelMatch = block.match(/^([^*\n]+)\*\*/);
541
+ const fieldIdMatch = block.match(/Field ID:\s*`([a-f0-9]{24})`/i);
542
+ const keyMatch = block.match(/Key:\s*`(\w+)`/i);
543
+ if (fieldIdMatch) {
544
+ const fieldId = fieldIdMatch[1];
545
+ if (labelMatch) {
546
+ schema.fields[labelMatch[1].trim()] = fieldId;
547
+ }
548
+ if (keyMatch) {
549
+ schema.fields[keyMatch[1]] = fieldId;
550
+ }
551
+ }
552
+ }
553
+ }
554
+ }
555
+ /**
556
+ * Map field keys to their IDs in the schema
557
+ * Since parseFields now stores by key directly, this is a no-op
558
+ * Kept for backwards compatibility but does nothing
559
+ */
560
+ mapFieldLabelsToIds(_schema, _keyMap) {
561
+ // parseFields now stores fields by key directly, so this is a no-op
562
+ }
563
+ /**
564
+ * Clear cache for a workspace (memory cache only)
565
+ */
566
+ clearCache(workspaceId) {
567
+ if (workspaceId) {
568
+ this.cache.delete(workspaceId);
569
+ this.logger.info("Cleared memory cache", { workspaceId });
570
+ }
571
+ else {
572
+ this.cache.clear();
573
+ this.logger.info("Cleared all memory caches");
574
+ }
575
+ }
576
+ }
577
+ exports.WorkspaceSchemaCacheService = WorkspaceSchemaCacheService;
578
+ //# sourceMappingURL=workspace-schema-cache.js.map