tide-commander 1.32.2 → 1.35.0

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 (80) hide show
  1. package/dist/assets/{BossLogsModal-2lqGyuCD.js → BossLogsModal-B_dgVF7L.js} +1 -1
  2. package/dist/assets/{BossSpawnModal-CR-ofDeB.js → BossSpawnModal-CSO1bYxA.js} +1 -1
  3. package/dist/assets/{ControlsModal-DQ8QVshA.js → ControlsModal-WMTTqbca.js} +1 -1
  4. package/dist/assets/{DockerLogsModal-D6yQTHy7.js → DockerLogsModal-THzhLHch.js} +1 -1
  5. package/dist/assets/{EmbeddedEditor-wechGxGl.js → EmbeddedEditor-DWLKJYav.js} +1 -1
  6. package/dist/assets/GmailOAuthSetup-DN9ceaS6.js +270 -0
  7. package/dist/assets/{GoogleOAuthSetup-BcpJEydM.js → GoogleOAuthSetup-bVST2EOB.js} +1 -1
  8. package/dist/assets/{IframeModal-E2E7NR08.js → IframeModal-BELsjvgi.js} +1 -1
  9. package/dist/assets/{IntegrationsPanel-CrS2QOFR.js → IntegrationsPanel-DwDr4BRt.js} +2 -2
  10. package/dist/assets/{LogViewerModal-BpIPZeFr.js → LogViewerModal-CMe04PO5.js} +1 -1
  11. package/dist/assets/MonitoringModal-CqSalNeY.js +1 -0
  12. package/dist/assets/{PM2LogsModal-CDk_2mi1.js → PM2LogsModal-CCmCDxVt.js} +1 -1
  13. package/dist/assets/{RestoreArchivedAreaModal-BmgBrk9J.js → RestoreArchivedAreaModal-IfzPidIv.js} +1 -1
  14. package/dist/assets/{SaveSnapshotModal-DWta9pcx.js → SaveSnapshotModal-DUhrVD5l.js} +1 -1
  15. package/dist/assets/{Scene2DCanvas-C3CcFsjU.js → Scene2DCanvas-Bl5DUC7w.js} +1 -1
  16. package/dist/assets/{SceneManager-mFUakRNl.js → SceneManager-BGO9tiaI.js} +1 -1
  17. package/dist/assets/{SkillsPanel-Br3h8GNh.js → SkillsPanel-CPFOI4Tl.js} +1 -1
  18. package/dist/assets/{SnapshotManager-CPYWfnPR.js → SnapshotManager-Cbu0tJBz.js} +1 -1
  19. package/dist/assets/{SpawnModal-DSDirR0j.js → SpawnModal-BqDbsYLY.js} +1 -1
  20. package/dist/assets/{SubordinateAssignmentModal-Daz67phV.js → SubordinateAssignmentModal-DOqkhL_L.js} +1 -1
  21. package/dist/assets/{SupervisorPanel-DoAl5e8W.js → SupervisorPanel-BvX-dlk_.js} +1 -1
  22. package/dist/assets/{TriggerManagerPanel-CVIHbqDt.js → TriggerManagerPanel-RUVFmKmf.js} +1 -1
  23. package/dist/assets/WorkflowEditorPanel-CwZpEqzM.js +42 -0
  24. package/dist/assets/browser-ponyfill-DZOWXZ4K.js +2 -0
  25. package/dist/assets/camera-D_KeL_pz.js +1 -0
  26. package/dist/assets/{index-I-I3pPPW.js → index-B-wV06cR.js} +1 -1
  27. package/dist/assets/index-BFguOWBW.js +2 -0
  28. package/dist/assets/{index-uXOqPsuU.js → index-C7gqY2AA.js} +1 -1
  29. package/dist/assets/{index-CE_GbjZ6.js → index-CiD1Rwaq.js} +1 -1
  30. package/dist/assets/index-D4nfDvz4.js +49 -0
  31. package/dist/assets/{index-CvMf5n2v.js → index-DDPUtz8-.js} +1 -1
  32. package/dist/assets/{index-Chrxgrys.js → index-EH8IBvSU.js} +1 -1
  33. package/dist/assets/{index-DWVQ48nQ.js → index-H0PzHVFw.js} +1 -1
  34. package/dist/assets/main-Cjm0d8dZ.js +152 -0
  35. package/dist/assets/main-DqC9_fF4.css +1 -0
  36. package/dist/assets/{prism-cpp-CcQnz8LL.js → prism-cpp-CK2Ly5dS.js} +1 -1
  37. package/dist/assets/{prism-csharp-DFIAaw4Y.js → prism-csharp-ByDDDiWW.js} +1 -1
  38. package/dist/assets/{prism-elixir-jP4m4T-8.js → prism-elixir-df27OMMQ.js} +1 -1
  39. package/dist/assets/{prism-haskell-BrMZM7_F.js → prism-haskell-Ce8aBmia.js} +1 -1
  40. package/dist/assets/{prism-java-BEsh8u4L.js → prism-java-CK6tws4L.js} +1 -1
  41. package/dist/assets/{prism-perl-ecHKp0bZ.js → prism-perl-UZfqnD51.js} +1 -1
  42. package/dist/assets/{prism-php-Ch-kk89U.js → prism-php-Dt9698bA.js} +1 -1
  43. package/dist/assets/{prism-ruby-zNpGDk6v.js → prism-ruby-CQBUuZIF.js} +1 -1
  44. package/dist/assets/{prism-scss-BeuXx0O0.js → prism-scss-CeN16CFC.js} +1 -1
  45. package/dist/assets/{vendor-react-uS-d4TUT.js → vendor-react--Eh9ivFN.js} +2 -2
  46. package/dist/assets/{web-IWJRtE3-.js → web-D1vWYL8u.js} +1 -1
  47. package/dist/assets/{web-DdRt5c0R.js → web-DUq3Undh.js} +1 -1
  48. package/dist/index.html +3 -3
  49. package/dist/src/packages/server/data/builtin-skills/boss-instructions.js +57 -66
  50. package/dist/src/packages/server/data/builtin-skills/index.js +2 -0
  51. package/dist/src/packages/server/data/builtin-skills/workflow-builder.js +253 -0
  52. package/dist/src/packages/server/data/builtin-skills/workflow-designer.js +157 -0
  53. package/dist/src/packages/server/data/event-queries.js +24 -0
  54. package/dist/src/packages/server/data/migrations/002_workflow_agent_binding.sql +14 -0
  55. package/dist/src/packages/server/data/migrations/003_matcher_executions.sql +19 -0
  56. package/dist/src/packages/server/data/migrations/004_matcher_message_source.sql +8 -0
  57. package/dist/src/packages/server/integrations/gmail/gmail-client.js +75 -15
  58. package/dist/src/packages/server/integrations/gmail/gmail-config.js +32 -2
  59. package/dist/src/packages/server/integrations/gmail/gmail-routes.js +5 -0
  60. package/dist/src/packages/server/integrations/gmail/index.js +23 -1
  61. package/dist/src/packages/server/integrations/jira/jira-client.js +11 -5
  62. package/dist/src/packages/server/integrations/jira/jira-routes.js +20 -3
  63. package/dist/src/packages/server/integrations/jira/jira-skill.js +110 -58
  64. package/dist/src/packages/server/routes/trigger-routes.js +22 -0
  65. package/dist/src/packages/server/routes/workflow-routes.js +86 -2
  66. package/dist/src/packages/server/services/boss-message-service.js +1 -1
  67. package/dist/src/packages/server/services/llm-matcher-service.js +50 -81
  68. package/dist/src/packages/server/services/trigger-service.js +195 -6
  69. package/dist/src/packages/server/services/workflow-executor.js +230 -0
  70. package/dist/src/packages/server/services/workflow-service.js +59 -13
  71. package/package.json +7 -7
  72. package/dist/assets/GmailOAuthSetup-B2GDjROU.js +0 -222
  73. package/dist/assets/MonitoringModal-CIF9MUm9.js +0 -1
  74. package/dist/assets/WorkflowEditorPanel-C4BRfmDM.js +0 -42
  75. package/dist/assets/browser-ponyfill-DIm4hKhx.js +0 -2
  76. package/dist/assets/camera-8crtHeRa.js +0 -1
  77. package/dist/assets/index--PCy0J0f.js +0 -49
  78. package/dist/assets/index-DOzx4Y9b.js +0 -2
  79. package/dist/assets/main-DQpuQfqS.css +0 -1
  80. package/dist/assets/main-DahZb6P4.js +0 -152
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Workflow Executor
3
+ * Orchestration layer for the Workflow-as-Agent architecture.
4
+ *
5
+ * Adds three capabilities on top of workflow-service.ts:
6
+ * 1. handleTrigger — routes an incoming trigger to the correct workflow instance
7
+ * 2. executeInstanceState — enters a state with agent binding and reasoning capture
8
+ * 3. transitionInstance — transitions with reasoning/summary capture
9
+ *
10
+ * The core state machine (enterState, evaluateTransitions, etc.) lives in
11
+ * workflow-service.ts. This module deals only with the agent binding,
12
+ * trigger routing, and reasoning-capture concerns.
13
+ */
14
+ import { createLogger } from '../utils/logger.js';
15
+ import * as workflowService from './workflow-service.js';
16
+ import * as workflowStore from '../data/workflow-store.js';
17
+ import * as eventQueries from '../data/event-queries.js';
18
+ const log = createLogger('WorkflowExecutor');
19
+ // ─── Handle Trigger ───
20
+ /**
21
+ * Route an incoming trigger to the matching workflow instance(s).
22
+ *
23
+ * Resolution order:
24
+ * 1. Find running workflow instances whose trigger_id matches the incoming triggerId.
25
+ * 2. If none found, search workflow definitions for states that reference this triggerId
26
+ * (via wait_for_trigger or trigger_setup actions) and create a new instance.
27
+ * 3. If still no match, log and return — the trigger is not wired to any workflow.
28
+ *
29
+ * When a match is found, the trigger data is forwarded to the instance via
30
+ * workflowService.notifyEvent so the state machine can evaluate transitions.
31
+ */
32
+ export async function handleTrigger(payload) {
33
+ const { triggerId, triggerData } = payload;
34
+ // 1. Try to find a running instance waiting for this trigger
35
+ const runningInstances = eventQueries.listWorkflowInstances({ status: 'running' });
36
+ const matchedInstances = runningInstances.filter(inst => {
37
+ // Check if the instance has this trigger in its active triggers
38
+ if (inst.activeTriggerIds.includes(triggerId))
39
+ return true;
40
+ // Check if the instance was started by this trigger
41
+ if (inst.triggerId === triggerId)
42
+ return true;
43
+ return false;
44
+ });
45
+ if (matchedInstances.length > 0) {
46
+ for (const instance of matchedInstances) {
47
+ log.log(`Routing trigger ${triggerId} to instance ${instance.id}`);
48
+ await workflowService.notifyEvent({
49
+ instanceId: instance.id,
50
+ eventType: 'trigger_fired',
51
+ triggerId,
52
+ data: triggerData,
53
+ });
54
+ }
55
+ return;
56
+ }
57
+ // 2. Search definitions for a state wired to this trigger
58
+ const definitions = workflowStore.listDefinitions();
59
+ const matchingDef = findDefinitionForTrigger(definitions, triggerId);
60
+ if (matchingDef) {
61
+ log.log(`Trigger ${triggerId} matched definition ${matchingDef.id} — starting new instance`);
62
+ const instance = await startWorkflowForTrigger(matchingDef, payload);
63
+ log.log(`Created instance ${instance.id} for trigger ${triggerId}`);
64
+ return;
65
+ }
66
+ // 3. No match
67
+ log.log(`Trigger ${triggerId} has no matching workflow — ignoring`);
68
+ }
69
+ /**
70
+ * Search workflow definitions for any state whose action references the given triggerId.
71
+ */
72
+ function findDefinitionForTrigger(definitions, triggerId) {
73
+ for (const def of definitions) {
74
+ for (const state of def.states) {
75
+ if (!state.action)
76
+ continue;
77
+ if (state.action.type === 'wait_for_trigger' && state.action.triggerId === triggerId) {
78
+ return def;
79
+ }
80
+ if (state.action.type === 'trigger_setup') {
81
+ const config = state.action.triggerConfig;
82
+ if (config.triggerId === triggerId)
83
+ return def;
84
+ }
85
+ // Also check transition conditions for trigger_fired with specific triggerId
86
+ for (const transition of state.transitions) {
87
+ if (transition.condition.type === 'trigger_fired' &&
88
+ transition.condition.triggerId === triggerId) {
89
+ return def;
90
+ }
91
+ }
92
+ }
93
+ }
94
+ return undefined;
95
+ }
96
+ /**
97
+ * Start a new workflow instance in response to a trigger fire.
98
+ * Binds the trigger correlation and optional agent ID to the instance.
99
+ */
100
+ async function startWorkflowForTrigger(def, payload) {
101
+ // Start the workflow through the existing service
102
+ const instance = await workflowService.startWorkflow({
103
+ workflowDefId: def.id,
104
+ initialVariables: payload.triggerData,
105
+ });
106
+ // Bind the trigger and agent correlation
107
+ eventQueries.updateWorkflowInstance(instance.id, {
108
+ triggerId: payload.triggerId,
109
+ triggerData: payload.triggerData,
110
+ agentId: payload.agentId,
111
+ updatedAt: Date.now(),
112
+ });
113
+ return eventQueries.getWorkflowInstance(instance.id);
114
+ }
115
+ // ─── Execute Instance State ───
116
+ /**
117
+ * Execute a specific state in a workflow instance, capturing agent binding.
118
+ *
119
+ * This is called when an agent is about to execute a state's action.
120
+ * It updates the step log with the agent ID and records the prompt being sent.
121
+ */
122
+ export function executeInstanceState(instanceId, stateId, agentId) {
123
+ const instance = eventQueries.getWorkflowInstance(instanceId);
124
+ if (!instance) {
125
+ throw new Error(`Workflow instance not found: ${instanceId}`);
126
+ }
127
+ if (instance.status !== 'running') {
128
+ throw new Error(`Instance ${instanceId} is not running (status: ${instance.status})`);
129
+ }
130
+ const def = workflowStore.getDefinition(instance.workflowDefId);
131
+ if (!def) {
132
+ throw new Error(`Workflow definition not found: ${instance.workflowDefId}`);
133
+ }
134
+ const state = def.states.find(s => s.id === stateId);
135
+ if (!state) {
136
+ throw new Error(`State ${stateId} not found in workflow ${def.id}`);
137
+ }
138
+ // Bind agent to instance if not already bound
139
+ if (!instance.agentId) {
140
+ eventQueries.updateWorkflowInstance(instanceId, {
141
+ agentId,
142
+ updatedAt: Date.now(),
143
+ });
144
+ }
145
+ // Update current step with the agent ID
146
+ const currentStep = eventQueries.getCurrentStep(instanceId);
147
+ if (currentStep) {
148
+ eventQueries.updateStepLog(currentStep.id, { agentId });
149
+ }
150
+ return { instance, state, currentStep };
151
+ }
152
+ // ─── Transition Instance ───
153
+ /**
154
+ * Transition a workflow instance to the next state, capturing reasoning and summary.
155
+ *
156
+ * This wraps workflowService.notifyEvent with reasoning capture:
157
+ * - agentResponse: the raw output from the agent
158
+ * - agentReasoning: the agent's chain-of-thought or decision explanation
159
+ * - agentSummary: a short human-readable summary for the timeline
160
+ */
161
+ export async function transitionInstance(instanceId, eventType, result, opts) {
162
+ const instance = eventQueries.getWorkflowInstance(instanceId);
163
+ if (!instance) {
164
+ log.error(`Cannot transition: instance ${instanceId} not found`);
165
+ return undefined;
166
+ }
167
+ // Capture reasoning on the current step before transitioning
168
+ const currentStep = eventQueries.getCurrentStep(instanceId);
169
+ if (currentStep) {
170
+ const stepUpdates = {};
171
+ if (result.agentResponse !== undefined) {
172
+ stepUpdates.agentResponse = result.agentResponse;
173
+ }
174
+ if (result.agentReasoning !== undefined) {
175
+ stepUpdates.agentReasoning = result.agentReasoning;
176
+ }
177
+ if (result.agentSummary !== undefined) {
178
+ stepUpdates.agentSummary = result.agentSummary;
179
+ }
180
+ if (Object.keys(stepUpdates).length > 0) {
181
+ eventQueries.updateStepLog(currentStep.id, stepUpdates);
182
+ }
183
+ }
184
+ // Build the event data payload (merge agent result variables)
185
+ const eventData = { ...result.variables };
186
+ if (result.agentResponse)
187
+ eventData.agentResponse = result.agentResponse;
188
+ if (result.agentReasoning)
189
+ eventData.agentReasoning = result.agentReasoning;
190
+ if (result.agentSummary)
191
+ eventData.agentSummary = result.agentSummary;
192
+ // Forward to the state machine
193
+ await workflowService.notifyEvent({
194
+ instanceId,
195
+ eventType,
196
+ triggerId: opts?.triggerId,
197
+ transitionId: opts?.transitionId,
198
+ data: Object.keys(eventData).length > 0 ? eventData : undefined,
199
+ });
200
+ return eventQueries.getWorkflowInstance(instanceId);
201
+ }
202
+ // ─── Query Helpers ───
203
+ /**
204
+ * Get all workflow instances bound to a specific agent.
205
+ */
206
+ export function getInstancesByAgent(agentId, opts) {
207
+ const allInstances = eventQueries.listWorkflowInstances({
208
+ status: opts?.status,
209
+ limit: opts?.limit ?? 50,
210
+ });
211
+ return allInstances.filter(inst => inst.agentId === agentId);
212
+ }
213
+ /**
214
+ * Get the reasoning chain for an instance, including agentSummary.
215
+ */
216
+ export function getReasoningChain(instanceId) {
217
+ const steps = eventQueries.getStepsByInstance(instanceId);
218
+ return steps
219
+ .filter(s => s.promptSent || s.agentResponse || s.agentSummary)
220
+ .map(s => ({
221
+ stateId: s.toStateId,
222
+ stateName: s.toStateName,
223
+ agentId: s.agentId,
224
+ promptSent: s.promptSent,
225
+ agentResponse: s.agentResponse,
226
+ agentReasoning: s.agentReasoning,
227
+ agentSummary: s.agentSummary,
228
+ durationMs: s.durationMs,
229
+ }));
230
+ }
@@ -151,12 +151,7 @@ export async function resumeWorkflow(instanceId) {
151
151
  });
152
152
  const updated = eventQueries.getWorkflowInstance(instanceId);
153
153
  emit({ instanceId, eventType: 'state_changed', data: updated });
154
- // Re-evaluate transitions (a trigger might have fired while paused)
155
- const def = workflowStore.getDefinition(updated.workflowDefId);
156
- if (def) {
157
- await evaluateTransitions(updated, def);
158
- }
159
- return eventQueries.getWorkflowInstance(instanceId);
154
+ return updated;
160
155
  }
161
156
  export function cancelWorkflow(instanceId) {
162
157
  const instance = eventQueries.getWorkflowInstance(instanceId);
@@ -251,11 +246,6 @@ async function enterState(instance, stateId, def) {
251
246
  }
252
247
  // Set up timeout transitions
253
248
  setupTimeoutTransitions(instance, state, def);
254
- // Evaluate auto-transitions (e.g. set_variables actions can trigger variable_check)
255
- const freshInstance = eventQueries.getWorkflowInstance(instance.id);
256
- if (freshInstance && freshInstance.status === 'running') {
257
- await evaluateTransitions(freshInstance, def);
258
- }
259
249
  }
260
250
  async function executeAction(instance, action, stepLogId) {
261
251
  switch (action.type) {
@@ -321,7 +311,7 @@ async function executeAction(instance, action, stepLogId) {
321
311
  }
322
312
  }
323
313
  }
324
- async function evaluateTransitions(instance, def) {
314
+ export async function evaluateTransitions(instance, def) {
325
315
  const state = def.states.find((s) => s.id === instance.currentStateId);
326
316
  if (!state)
327
317
  return;
@@ -454,6 +444,7 @@ export async function notifyEvent(params) {
454
444
  eventQueries.updateStepLog(currentStep.id, {
455
445
  agentResponse: params.data.agentResponse,
456
446
  agentReasoning: params.data.agentReasoning,
447
+ agentSummary: params.data.agentSummary,
457
448
  });
458
449
  }
459
450
  }
@@ -501,6 +492,60 @@ export async function notifyEvent(params) {
501
492
  }
502
493
  }
503
494
  }
495
+ // ─── Explicit Transition (agent-driven) ───
496
+ export async function transitionTo(instanceId, targetStateId, reason) {
497
+ const instance = eventQueries.getWorkflowInstance(instanceId);
498
+ if (!instance)
499
+ throw new Error(`Workflow instance not found: ${instanceId}`);
500
+ if (instance.status !== 'running')
501
+ throw new Error(`Instance ${instanceId} is not running (status: ${instance.status})`);
502
+ const def = workflowStore.getDefinition(instance.workflowDefId);
503
+ if (!def)
504
+ throw new Error(`Workflow definition not found: ${instance.workflowDefId}`);
505
+ const state = def.states.find(s => s.id === instance.currentStateId);
506
+ if (!state)
507
+ throw new Error(`Current state not found: ${instance.currentStateId}`);
508
+ // Find a transition that targets the requested state
509
+ const transition = state.transitions.find(t => t.targetStateId === targetStateId);
510
+ if (!transition) {
511
+ const validTargets = state.transitions.map(t => t.targetStateId).join(', ');
512
+ throw new Error(`No transition from "${state.name}" to "${targetStateId}". Valid targets: ${validTargets}`);
513
+ }
514
+ log.log(`Explicit transition: ${instance.currentStateId} → ${targetStateId} (reason: ${reason ?? 'none'})`);
515
+ // Log the reason in audit
516
+ eventQueries.logAudit({
517
+ category: 'workflow',
518
+ action: 'explicit_transition',
519
+ workflowInstanceId: instanceId,
520
+ details: { from: instance.currentStateId, to: targetStateId, transitionId: transition.id, reason },
521
+ level: 'info',
522
+ createdAt: Date.now(),
523
+ });
524
+ await handleTransition(instance, transition, def);
525
+ return eventQueries.getWorkflowInstance(instanceId);
526
+ }
527
+ export function getAvailableTransitions(instanceId) {
528
+ const instance = eventQueries.getWorkflowInstance(instanceId);
529
+ if (!instance)
530
+ throw new Error(`Workflow instance not found: ${instanceId}`);
531
+ const def = workflowStore.getDefinition(instance.workflowDefId);
532
+ if (!def)
533
+ throw new Error(`Workflow definition not found: ${instance.workflowDefId}`);
534
+ const state = def.states.find(s => s.id === instance.currentStateId);
535
+ if (!state)
536
+ return [];
537
+ return state.transitions.map(t => {
538
+ const targetState = def.states.find(s => s.id === t.targetStateId);
539
+ return {
540
+ id: t.id,
541
+ name: t.name,
542
+ targetStateId: t.targetStateId,
543
+ targetStateName: targetState?.name ?? 'unknown',
544
+ conditionType: t.condition.type,
545
+ condition: t.condition,
546
+ };
547
+ });
548
+ }
504
549
  // ─── Variable Updates (called by agents via API) ───
505
550
  export function updateVariables(instanceId, updates, changedBy) {
506
551
  const instance = eventQueries.getWorkflowInstance(instanceId);
@@ -560,7 +605,7 @@ export function getInstanceVariableHistory(instanceId, variableName) {
560
605
  export function getInstanceReasoning(instanceId) {
561
606
  const steps = eventQueries.getStepsByInstance(instanceId);
562
607
  return steps
563
- .filter((s) => s.promptSent || s.agentResponse)
608
+ .filter((s) => s.promptSent || s.agentResponse || s.agentSummary)
564
609
  .map((s) => ({
565
610
  stateId: s.toStateId,
566
611
  stateName: s.toStateName,
@@ -568,6 +613,7 @@ export function getInstanceReasoning(instanceId) {
568
613
  promptSent: s.promptSent,
569
614
  agentResponse: s.agentResponse,
570
615
  agentReasoning: s.agentReasoning,
616
+ agentSummary: s.agentSummary,
571
617
  durationMs: s.durationMs,
572
618
  }));
573
619
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.32.2",
3
+ "version": "1.35.0",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,7 +36,7 @@
36
36
  "tc": "tsx tools/tc.ts"
37
37
  },
38
38
  "dependencies": {
39
- "@anthropic-ai/sdk": "^0.71.2",
39
+ "@anthropic-ai/sdk": "^0.81.0",
40
40
  "@capacitor/haptics": "^8.0.1",
41
41
  "@capacitor/local-notifications": "^8.0.1",
42
42
  "@codemirror/lang-cpp": "^6.0.3",
@@ -69,7 +69,7 @@
69
69
  "@xterm/xterm": "^6.0.0",
70
70
  "archiver": "^7.0.1",
71
71
  "better-sqlite3": "^12.8.0",
72
- "chokidar": "^4.0.0",
72
+ "chokidar": "^5.0.0",
73
73
  "codemirror": "^6.0.2",
74
74
  "cors": "^2.8.5",
75
75
  "croner": "^10.0.1",
@@ -79,7 +79,7 @@
79
79
  "fuse.js": "^7.1.0",
80
80
  "googleapis": "^171.4.0",
81
81
  "http-proxy": "^1.18.1",
82
- "i18next": "^25.8.7",
82
+ "i18next": "^26.0.3",
83
83
  "i18next-browser-languagedetector": "^8.2.1",
84
84
  "i18next-http-backend": "^3.0.2",
85
85
  "mssql": "^12.2.1",
@@ -92,7 +92,7 @@
92
92
  "react": "^19.2.3",
93
93
  "react-datepicker": "^9.1.0",
94
94
  "react-dom": "^19.2.3",
95
- "react-i18next": "^16.5.4",
95
+ "react-i18next": "^17.0.2",
96
96
  "react-markdown": "^10.1.0",
97
97
  "remark-gfm": "^4.0.1",
98
98
  "three": "^0.170.0",
@@ -100,11 +100,11 @@
100
100
  "ws": "^8.18.0"
101
101
  },
102
102
  "overrides": {
103
- "tar": "7.5.7"
103
+ "tar": "7.5.13"
104
104
  },
105
105
  "devDependencies": {
106
106
  "@capacitor/android": "^8.1.0",
107
- "@capacitor/cli": "^7.5.0",
107
+ "@capacitor/cli": "^8.3.0",
108
108
  "@capacitor/core": "^8.1.0",
109
109
  "@types/archiver": "^7.0.0",
110
110
  "@types/cors": "^2.8.19",
@@ -1,222 +0,0 @@
1
- import{r as t,L as E,p as v,j as e}from"./main-DahZb6P4.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react-uS-d4TUT.js";import"./vendor-three-Chj50gSY.js";function T({integration:l,onSave:x,onCancel:j}){const[d,R]=t.useState(l.values.clientId||""),[b,U]=t.useState(""),[g,w]=t.useState(String(l.values.pollingIntervalMs??3e4)),[p,N]=t.useState(l.values.defaultApprovalKeywords||"approved,aprobado,autorizado,yes,ok"),[y,k]=t.useState(null),[o,C]=t.useState(null),[u,h]=t.useState(!1),[A,r]=t.useState(null),[S,z]=t.useState(!1),[c,s]=t.useState(l.status.connected?"connected":"credentials"),i=t.useRef(null),I=t.useRef(l.status.connected),m=t.useCallback(async()=>{try{const a=await E(v("/api/email/status"));if(a.ok){const n=await a.json();C(n),n.authenticated&&(s("connected"),i.current&&(clearInterval(i.current),i.current=null))}}catch(a){console.error("Failed to fetch Gmail status:",a)}},[]);t.useEffect(()=>{const a=l.status.connected,n=I.current;a&&!n&&c!=="connected"?s("connected"):!a&&n&&c==="connected"&&s("credentials"),I.current=a},[l.status.connected]),t.useEffect(()=>(m(),()=>{i.current&&clearInterval(i.current)}),[m]);const G=async()=>{if(!d.trim()){r("Client ID is required");return}h(!0),r(null);try{const a={clientId:d.trim(),pollingIntervalMs:parseInt(g)||3e4,defaultApprovalKeywords:p};b.trim()&&(a.clientSecret=b.trim()),console.log("Saving Gmail config...",a),await x(a),console.log("Config saved successfully"),console.log("Fetching OAuth URL...");const n=await E(v("/api/email/auth/url"));if(console.log("OAuth URL response:",n.status),!n.ok){const M=await n.json().catch(()=>({}));throw new Error(M.error||`HTTP ${n.status}`)}const f=await n.json();if(console.log("Received OAuth URL:",f),console.log("Setting authUrl to:",f.url),!f.url)throw new Error("OAuth URL is empty");k(f.url),console.log("AuthUrl state updated"),r(null),s("authorize"),console.log("Step updated to authorize",{step:"authorize"}),i.current&&clearInterval(i.current),i.current=setInterval(m,3e3),console.log("Started polling for auth completion")}catch(a){const n=a instanceof Error?a.message:"Failed to get OAuth URL";console.error("Error in handleSaveCredentials:",n,a),r(n)}finally{h(!1)}},O=async()=>{z(!0),r(null);try{await x({pollingIntervalMs:parseInt(g)||3e4,defaultApprovalKeywords:p})}catch(a){r(a instanceof Error?a.message:"Failed to save settings")}finally{z(!1)}},L=async()=>{h(!0),r(null);try{await x({refreshToken:""}),C(null),k(null),s("credentials"),await m()}catch(a){r(a instanceof Error?a.message:"Failed to disconnect")}finally{h(!1)}};return e.jsxs("div",{className:"gmail-oauth-setup",children:[A&&e.jsx("div",{className:"gmail-oauth-error",children:A}),c==="credentials"&&e.jsxs("div",{className:"gmail-oauth-section",children:[e.jsx("h4",{className:"gmail-oauth-section-title",children:"Google OAuth Credentials"}),e.jsxs("p",{className:"gmail-oauth-help",children:["Create OAuth2 credentials in the"," ",e.jsx("a",{href:"https://console.cloud.google.com/apis/credentials",target:"_blank",rel:"noopener noreferrer",className:"gmail-oauth-link",children:"Google Cloud Console"}),". Enable the Gmail API and (optionally) the Calendar API. Set the redirect URI to:"," ",e.jsx("code",{className:"gmail-oauth-code",children:v("/api/email/auth/callback")})]}),e.jsxs("div",{className:"gmail-oauth-field",children:[e.jsxs("label",{className:"integration-field-label",children:["OAuth Client ID ",e.jsx("span",{className:"integration-field-required",children:"*"})]}),e.jsx("input",{type:"text",className:"integration-field-input",value:d,placeholder:"xxxx.apps.googleusercontent.com",onChange:a=>R(a.target.value)})]}),e.jsxs("div",{className:"gmail-oauth-field",children:[e.jsxs("label",{className:"integration-field-label",children:["OAuth Client Secret ",e.jsx("span",{className:"integration-field-required",children:"*"})]}),e.jsx("input",{type:"password",className:"integration-field-input",value:b,placeholder:l.values.clientSecret?"(saved)":"Enter client secret",onChange:a=>U(a.target.value),autoComplete:"off"})]}),e.jsxs("div",{className:"gmail-oauth-field",children:[e.jsx("label",{className:"integration-field-label",children:"Polling Interval (ms)"}),e.jsx("input",{type:"number",className:"integration-field-input",value:g,onChange:a=>w(a.target.value)}),e.jsx("span",{className:"integration-field-description",children:"How often to check for new emails. Default: 30000 (30s)."})]}),e.jsxs("div",{className:"gmail-oauth-field",children:[e.jsx("label",{className:"integration-field-label",children:"Approval Keywords"}),e.jsx("textarea",{className:"integration-field-input integration-field-textarea",value:p,onChange:a=>N(a.target.value),rows:2}),e.jsx("span",{className:"integration-field-description",children:"Comma-separated keywords that indicate email approval."})]}),e.jsxs("div",{className:"integration-form-actions",children:[e.jsx("button",{type:"button",className:"integration-btn cancel",onClick:j,children:"Cancel"}),e.jsx("button",{type:"button",className:"integration-btn save",onClick:G,disabled:u||!d.trim(),children:u?"Saving...":"Save & Authorize"})]})]}),c==="authorize"&&e.jsxs("div",{className:"gmail-oauth-section",children:[e.jsx("h4",{className:"gmail-oauth-section-title",children:"Authorize Gmail Access"}),e.jsx("p",{className:"gmail-oauth-help",children:"Click the link below to authorize Tide Commander to access your Gmail account. After granting access, you will be redirected back and the connection will be established automatically."}),y&&e.jsx("a",{href:y,target:"_blank",rel:"noopener noreferrer",className:"gmail-oauth-authorize-btn",children:"Authorize with Google"}),e.jsxs("div",{className:"gmail-oauth-waiting",children:[e.jsx("span",{className:"gmail-oauth-spinner"}),e.jsx("span",{children:"Waiting for authorization to complete..."})]}),e.jsx("div",{className:"integration-form-actions",children:e.jsx("button",{type:"button",className:"integration-btn cancel",onClick:()=>{i.current&&(clearInterval(i.current),i.current=null),s("credentials")},children:"Back"})})]}),c==="connected"&&e.jsxs("div",{className:"gmail-oauth-section",children:[e.jsx("h4",{className:"gmail-oauth-section-title",children:"Gmail Connected"}),e.jsxs("div",{className:"gmail-oauth-connected-info",children:[e.jsx("span",{className:"gmail-oauth-connected-badge",children:"Connected"}),(o==null?void 0:o.emailAddress)&&e.jsx("span",{className:"gmail-oauth-email",children:o.emailAddress})]}),(o==null?void 0:o.pollingActive)&&e.jsxs("p",{className:"gmail-oauth-help",children:["Email polling is active.",o.lastPollAt&&e.jsxs(e.Fragment,{children:[" Last checked: ",new Date(o.lastPollAt).toLocaleTimeString()]})]}),e.jsxs("div",{className:"gmail-oauth-field",children:[e.jsx("label",{className:"integration-field-label",children:"Polling Interval (ms)"}),e.jsx("input",{type:"number",className:"integration-field-input",value:g,onChange:a=>w(a.target.value)})]}),e.jsxs("div",{className:"gmail-oauth-field",children:[e.jsx("label",{className:"integration-field-label",children:"Approval Keywords"}),e.jsx("textarea",{className:"integration-field-input integration-field-textarea",value:p,onChange:a=>N(a.target.value),rows:2})]}),e.jsxs("div",{className:"integration-form-actions",children:[e.jsx("button",{type:"button",className:"integration-btn cancel",onClick:j,children:"Close"}),e.jsx("button",{type:"button",className:"integration-btn",style:{backgroundColor:"#f38ba8",color:"#1e1e2e"},onClick:L,disabled:u,children:u?"Disconnecting...":"Disconnect"}),e.jsx("button",{type:"button",className:"integration-btn save",onClick:O,disabled:S,children:S?"Saving...":"Save Settings"})]})]}),e.jsx("style",{children:`
2
- .gmail-oauth-setup {
3
- padding: 0;
4
- }
5
- .gmail-oauth-error {
6
- background: linear-gradient(135deg, rgba(243, 139, 168, 0.2) 0%, rgba(243, 139, 168, 0.08) 100%);
7
- border-left: 3px solid #f38ba8;
8
- color: #f38ba8;
9
- padding: 12px 16px;
10
- border-radius: 8px;
11
- margin-bottom: 18px;
12
- font-size: 13px;
13
- font-weight: 500;
14
- }
15
- .gmail-oauth-section {
16
- background: linear-gradient(180deg, rgba(45, 49, 69, 0.4) 0%, rgba(30, 30, 46, 0.2) 100%);
17
- border: 1px solid rgba(137, 180, 250, 0.15);
18
- border-radius: 12px;
19
- padding: 28px;
20
- backdrop-filter: blur(10px);
21
- }
22
- .gmail-oauth-section-title {
23
- margin: 0 0 16px 0;
24
- color: #cdd6f4;
25
- font-size: 18px;
26
- font-weight: 700;
27
- letter-spacing: -0.5px;
28
- }
29
- .gmail-oauth-help {
30
- color: #a6adc8;
31
- font-size: 13px;
32
- line-height: 1.6;
33
- margin: 0 0 20px 0;
34
- font-weight: 400;
35
- }
36
- .gmail-oauth-link {
37
- color: #89b4fa;
38
- text-decoration: none;
39
- border-bottom: 1.5px solid rgba(137, 180, 250, 0.4);
40
- transition: all 0.2s ease;
41
- font-weight: 500;
42
- }
43
- .gmail-oauth-link:hover {
44
- color: #a8c5ff;
45
- border-bottom-color: #89b4fa;
46
- }
47
- .gmail-oauth-code {
48
- background: rgba(137, 180, 250, 0.15);
49
- color: #89b4fa;
50
- padding: 4px 10px;
51
- border-radius: 6px;
52
- font-size: 12px;
53
- word-break: break-all;
54
- font-weight: 500;
55
- font-family: 'Monaco', 'Menlo', monospace;
56
- }
57
- .gmail-oauth-field {
58
- margin-bottom: 18px;
59
- }
60
- .integration-field-label {
61
- display: block;
62
- margin-bottom: 8px;
63
- color: #cdd6f4;
64
- font-size: 14px;
65
- font-weight: 600;
66
- letter-spacing: 0.3px;
67
- }
68
- .integration-field-required {
69
- color: #f38ba8;
70
- }
71
- .integration-field-input {
72
- width: 100%;
73
- background: rgba(30, 30, 46, 0.6);
74
- border: 1.5px solid rgba(137, 180, 250, 0.2);
75
- color: #cdd6f4;
76
- padding: 11px 14px;
77
- border-radius: 8px;
78
- font-size: 13px;
79
- transition: all 0.2s ease;
80
- font-weight: 500;
81
- }
82
- .integration-field-input:focus {
83
- outline: none;
84
- border-color: #89b4fa;
85
- background: rgba(30, 30, 46, 0.8);
86
- box-shadow: 0 0 0 3px rgba(137, 180, 250, 0.15);
87
- }
88
- .integration-field-input::placeholder {
89
- color: #6c7086;
90
- }
91
- .integration-field-textarea {
92
- resize: vertical;
93
- min-height: 80px;
94
- font-family: 'Monaco', 'Menlo', monospace;
95
- font-size: 12px;
96
- }
97
- .integration-field-description {
98
- display: block;
99
- margin-top: 7px;
100
- color: #7f849c;
101
- font-size: 12px;
102
- font-weight: 400;
103
- }
104
- .gmail-oauth-authorize-btn {
105
- display: inline-block;
106
- background: linear-gradient(135deg, #89b4fa 0%, #7aa3f0 100%);
107
- color: #1e1e2e;
108
- padding: 12px 32px;
109
- border-radius: 8px;
110
- text-decoration: none;
111
- font-weight: 700;
112
- font-size: 14px;
113
- margin-bottom: 20px;
114
- transition: all 0.25s ease;
115
- border: none;
116
- cursor: pointer;
117
- box-shadow: 0 4px 12px rgba(137, 180, 250, 0.25);
118
- letter-spacing: 0.3px;
119
- }
120
- .gmail-oauth-authorize-btn:hover {
121
- transform: translateY(-2px);
122
- box-shadow: 0 6px 16px rgba(137, 180, 250, 0.35);
123
- background: linear-gradient(135deg, #a8c5ff 0%, #8eb8ff 100%);
124
- }
125
- .gmail-oauth-authorize-btn:active {
126
- transform: translateY(0);
127
- }
128
- .gmail-oauth-waiting {
129
- display: flex;
130
- align-items: center;
131
- gap: 12px;
132
- color: #a6adc8;
133
- font-size: 13px;
134
- margin-bottom: 20px;
135
- background: rgba(137, 180, 250, 0.08);
136
- padding: 14px 16px;
137
- border-radius: 8px;
138
- border-left: 3px solid #89b4fa;
139
- font-weight: 500;
140
- }
141
- .gmail-oauth-spinner {
142
- display: inline-block;
143
- width: 16px;
144
- height: 16px;
145
- border: 2.5px solid rgba(137, 180, 250, 0.25);
146
- border-top-color: #89b4fa;
147
- border-radius: 50%;
148
- animation: gmail-spin 0.8s linear infinite;
149
- flex-shrink: 0;
150
- }
151
- @keyframes gmail-spin {
152
- to { transform: rotate(360deg); }
153
- }
154
- .gmail-oauth-connected-info {
155
- display: flex;
156
- align-items: center;
157
- gap: 14px;
158
- margin-bottom: 20px;
159
- background: rgba(166, 227, 161, 0.08);
160
- padding: 16px;
161
- border-radius: 10px;
162
- border-left: 3px solid #a6e3a1;
163
- }
164
- .gmail-oauth-connected-badge {
165
- background: linear-gradient(135deg, rgba(166, 227, 161, 0.3) 0%, rgba(166, 227, 161, 0.15) 100%);
166
- color: #a6e3a1;
167
- padding: 6px 14px;
168
- border-radius: 6px;
169
- font-size: 12px;
170
- font-weight: 700;
171
- letter-spacing: 0.4px;
172
- text-transform: uppercase;
173
- border: 1px solid rgba(166, 227, 161, 0.3);
174
- flex-shrink: 0;
175
- }
176
- .gmail-oauth-email {
177
- color: #cdd6f4;
178
- font-size: 14px;
179
- font-weight: 600;
180
- letter-spacing: 0.2px;
181
- }
182
- .integration-form-actions {
183
- display: flex;
184
- gap: 12px;
185
- justify-content: flex-end;
186
- margin-top: 24px;
187
- padding-top: 20px;
188
- border-top: 1px solid rgba(137, 180, 250, 0.1);
189
- }
190
- .integration-btn {
191
- padding: 10px 24px;
192
- border-radius: 8px;
193
- font-weight: 600;
194
- font-size: 13px;
195
- border: none;
196
- cursor: pointer;
197
- transition: all 0.2s ease;
198
- letter-spacing: 0.3px;
199
- }
200
- .integration-btn.save {
201
- background: linear-gradient(135deg, #89b4fa 0%, #7aa3f0 100%);
202
- color: #1e1e2e;
203
- box-shadow: 0 4px 12px rgba(137, 180, 250, 0.25);
204
- }
205
- .integration-btn.save:hover:not(:disabled) {
206
- transform: translateY(-2px);
207
- box-shadow: 0 6px 16px rgba(137, 180, 250, 0.35);
208
- }
209
- .integration-btn.cancel {
210
- background: rgba(137, 180, 250, 0.1);
211
- color: #89b4fa;
212
- border: 1.5px solid rgba(137, 180, 250, 0.2);
213
- }
214
- .integration-btn.cancel:hover:not(:disabled) {
215
- background: rgba(137, 180, 250, 0.15);
216
- border-color: #89b4fa;
217
- }
218
- .integration-btn:disabled {
219
- opacity: 0.5;
220
- cursor: not-allowed;
221
- }
222
- `})]})}export{T as GmailOAuthSetup};
@@ -1 +0,0 @@
1
- import{r as i,L as j,p as w,j as e}from"./main-DahZb6P4.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react-uS-d4TUT.js";import"./vendor-three-Chj50gSY.js";const O=[{id:"triggers",label:"Triggers",icon:"⚡"},{id:"workflows",label:"Workflows",icon:"⚙️"},{id:"messages",label:"Messages",icon:"💬"},{id:"stats",label:"Stats",icon:"📊"}],_={trigger:"#89b4fa",slack:"#cba6f7",email:"#f9e2af",calendar:"#a6e3a1",document:"#fab387",jira:"#89dceb",workflow:"#f38ba8",system:"#6c7086",step:"#f38ba8",variable_change:"#cba6f7",approval:"#a6e3a1",audit:"#6c7086"},J={trigger:"Trigger",slack:"Slack",email:"Email",calendar:"Calendar",document:"Document",jira:"Jira",workflow:"Workflow",system:"System",step:"Step",variable_change:"Variable",approval:"Approval",audit:"Audit"};function Z({isOpen:n,onClose:t}){const[r,h]=i.useState("triggers"),[S,o]=i.useState([]),[l,u]=i.useState(!0),[$,c]=i.useState(null),[m,R]=i.useState("24h"),[C,z]=i.useState(""),[W,I]=i.useState(null),[D,M]=i.useState(null),[P,U]=i.useState([]),T=i.useCallback(async()=>{if(r!=="stats"){u(!0);try{const a=Date.now(),b={"1h":36e5,"6h":216e5,"24h":864e5,"7d":6048e5,all:0},d=b[m]>0?String(a-b[m]):void 0;let v=[];if(r==="triggers"){const g=new URLSearchParams({limit:"200"});d&&g.set("since",d);const p=await j(w(`/api/events/triggers?${g}`));if(!p.ok){c(`HTTP ${p.status}`);return}v=((await p.json()).events||[]).map(x=>({type:"trigger",timestamp:x.firedAt,data:x}))}else if(r==="workflows"){const g=new URLSearchParams({limit:"200",category:"workflow"});d&&g.set("since",d);const p=await j(w(`/api/events/audit?${g}`));if(!p.ok){c(`HTTP ${p.status}`);return}v=((await p.json()).entries||[]).map(x=>({type:"workflow",timestamp:x.createdAt,data:x}))}else if(r==="messages"){const g=new URLSearchParams({limit:"200"}),p=new URLSearchParams({limit:"200"}),E=new URLSearchParams({limit:"200"});d&&(g.set("since",d),p.set("since",d));const[x,F,N]=await Promise.all([j(w(`/api/events/slack?${g}`)),j(w(`/api/events/email?${p}`)),j(w(`/api/events/approvals?${E}`))]);if(x.ok){const y=await x.json();for(const f of y.messages||[])v.push({type:"slack",timestamp:f.receivedAt,data:f})}if(F.ok){const y=await F.json();for(const f of y.messages||[])v.push({type:"email",timestamp:f.receivedAt,data:f})}if(N.ok){const y=await N.json();for(const f of y.events||[])v.push({type:"approval",timestamp:f.recordedAt,data:f})}v.sort((y,f)=>f.timestamp-y.timestamp)}o(v),c(null)}catch(a){c(`Failed to load events: ${a}`)}finally{u(!1)}}},[r,m]),A=i.useCallback(async()=>{u(!0);try{const[a,b]=await Promise.all([j(w("/api/events/stats")),j(w("/api/integrations"))]);if(a.ok&&M(await a.json()),b.ok){const d=await b.json();U(Array.isArray(d)?d:[])}c(null)}catch(a){c(`Failed to load stats: ${a}`)}finally{u(!1)}},[]);i.useEffect(()=>{n&&(r==="stats"?A():T())},[n,r,T,A]);const B=S.filter(a=>{if(!C)return!0;const b=C.toLowerCase();return JSON.stringify(a.data).toLowerCase().includes(b)});if(!n)return null;const H=P.filter(a=>a.status.connected).length;return e.jsx("div",{style:s.overlay,onClick:t,children:e.jsxs("div",{style:s.modal,onClick:a=>a.stopPropagation(),children:[e.jsxs("div",{style:s.header,children:[e.jsxs("div",{style:s.headerTitle,children:[e.jsx("span",{children:"📊"}),e.jsx("span",{children:"Monitoring & Logs"})]}),e.jsx("button",{style:s.closeBtn,onClick:t,title:"Close",children:"×"})]}),e.jsx("div",{style:s.tabs,children:O.map(a=>e.jsxs("button",{style:s.tab(r===a.id),onClick:()=>{h(a.id),z(""),I(null)},children:[e.jsx("span",{children:a.icon}),e.jsx("span",{children:a.label})]},a.id))}),r!=="stats"&&e.jsxs("div",{style:s.filters,children:[e.jsx("div",{style:{display:"flex",gap:4},children:["1h","6h","24h","7d","all"].map(a=>e.jsx("button",{style:{...s.timeBtn,background:m===a?"#89b4fa":"transparent",color:m===a?"#1e1e2e":"#a6adc8"},onClick:()=>R(a),children:a},a))}),e.jsx("input",{style:s.searchInput,placeholder:"Search events...",value:C,onChange:a=>z(a.target.value)}),e.jsx("button",{style:s.refreshBtn,onClick:T,children:"Refresh"})]}),e.jsx("div",{style:s.content,children:r==="stats"?e.jsx(V,{loading:l,error:$,stats:D,integrations:P,connectedCount:H,onRefresh:A}):e.jsx(G,{loading:l,error:$,entries:B,expandedId:W,onToggleExpand:a=>I(W===a?null:a)})}),r!=="stats"&&e.jsx("div",{style:s.footer,children:e.jsxs("span",{style:{color:"#6c7086",fontSize:11},children:[B.length," event",B.length!==1?"s":""," shown",C&&` (filtered from ${S.length})`]})})]})})}function G({loading:n,error:t,entries:r,expandedId:h,onToggleExpand:S}){return n?e.jsx("div",{style:{color:"#a6adc8",padding:20},children:"Loading events..."}):t?e.jsx("div",{style:{color:"#f38ba8",padding:20},children:t}):r.length===0?e.jsx("div",{style:{color:"#6c7086",textAlign:"center",padding:40},children:"No events found for the selected filters."}):e.jsx(e.Fragment,{children:r.map((o,l)=>{const u=`${o.type}-${o.timestamp}-${l}`,$=h===u,c=_[o.type]||"#6c7086",m=Y(o),R=new Date(o.timestamp);return e.jsxs("div",{style:{...s.eventRow,borderLeft:`3px solid ${c}`,background:$?"rgba(137,180,250,0.05)":"transparent"},onClick:()=>S(u),children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx("span",{style:{...s.tag,background:`${c}22`,color:c},children:J[o.type]||o.type}),e.jsx("span",{style:{color:"#cdd6f4",fontSize:12,flex:1},children:m}),e.jsxs("span",{style:{color:"#6c7086",fontSize:10,whiteSpace:"nowrap"},children:[R.toLocaleTimeString()," ",R.toLocaleDateString()]})]}),$&&e.jsx("pre",{style:s.detail,children:JSON.stringify(o.data,null,2)})]},u)})})}function V({loading:n,error:t,stats:r,integrations:h,connectedCount:S,onRefresh:o}){return n?e.jsx("div",{style:{color:"#a6adc8",padding:20},children:"Loading stats..."}):t?e.jsx("div",{style:{color:"#f38ba8",padding:20},children:t}):e.jsxs("div",{style:{padding:20},children:[e.jsx("div",{style:{display:"flex",justifyContent:"flex-end",marginBottom:16},children:e.jsx("button",{style:s.refreshBtn,onClick:o,children:"Refresh"})}),r&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:s.section,children:[e.jsx("h3",{style:s.sectionTitle,children:"Workflows"}),e.jsxs("div",{style:s.grid,children:[e.jsx(k,{label:"Active",value:r.activeWorkflows,color:"#89b4fa"}),e.jsx(k,{label:"Completed",value:r.completedWorkflows,color:"#a6e3a1"}),e.jsx(k,{label:"Failed",value:r.failedWorkflows,color:"#f38ba8"})]})]}),e.jsxs("div",{style:s.section,children:[e.jsx("h3",{style:s.sectionTitle,children:"Events (Today)"}),e.jsxs("div",{style:s.grid,children:[e.jsx(k,{label:"Triggers Fired",value:r.triggersFiredToday,color:"#f9e2af"}),e.jsx(k,{label:"Slack Messages",value:r.slackMessageCount,color:"#cba6f7"}),e.jsx(k,{label:"Emails",value:r.emailCount,color:"#fab387"})]})]}),e.jsxs("div",{style:s.section,children:[e.jsxs("h3",{style:s.sectionTitle,children:["Integrations (",S,"/",h.length," connected)"]}),e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:6},children:[h.map(l=>e.jsxs("div",{style:s.integrationRow,children:[e.jsx("span",{style:{color:"#cdd6f4",fontSize:13},children:l.name}),e.jsx("span",{style:{...s.statusBadge,background:l.status.connected?"rgba(166,227,161,0.15)":"rgba(108,112,134,0.15)",color:l.status.connected?"#a6e3a1":"#6c7086"},children:l.status.error?"Error":l.status.connected?"Connected":"Disconnected"})]},l.id)),h.length===0&&e.jsx("div",{style:{color:"#6c7086",fontSize:12},children:"No integrations configured"})]})]})]}),!r&&e.jsx("div",{style:{color:"#6c7086",textAlign:"center",padding:40},children:"No stats available. The event store may not have any data yet."})]})}function k({label:n,value:t,color:r}){return e.jsxs("div",{style:s.card,children:[e.jsx("div",{style:{color:r,fontSize:28,fontWeight:700,lineHeight:1},children:t}),e.jsx("div",{style:{color:"#a6adc8",fontSize:11,marginTop:4},children:n})]})}function Y(n){const t=n.data;switch(n.type){case"trigger":return`Trigger "${t.triggerName||t.triggerId}" ${t.status||"fired"}`;case"slack":return`${t.direction==="outbound"?"Sent":"Received"} in #${t.channelName||t.channelId}: ${L(t.text,60)}`;case"email":return`${t.direction==="outbound"?"Sent to":"From"} ${t.direction==="outbound"?t.toAddresses:t.fromAddress}: ${L(t.subject,50)}`;case"approval":return`${t.approved?"Approved":"Rejected"} by ${t.approverEmail}`;case"document":return`Generated "${t.outputFilename}" from template "${t.templateName}"`;case"calendar":return`Calendar event ${t.action}: "${t.summary}"`;case"jira":return`${t.ticketKey} ${t.action}: ${L(t.summary,50)}`;case"step":return`Workflow step: ${t.toStateName} (${t.status})`;case"variable_change":return`Variable "${t.variableName}" changed by ${t.changedBy}`;case"audit":return`[${(t.level||"info").toUpperCase()}] ${t.category}: ${t.action}`;default:return JSON.stringify(t).slice(0,80)}}function L(n,t){return n?n.length>t?n.slice(0,t)+"...":n:""}const s={overlay:{position:"fixed",inset:0,background:"rgba(0, 0, 0, 0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:1e4,backdropFilter:"blur(4px)"},modal:{background:"var(--surface-0, #1e1e2e)",borderRadius:12,border:"1px solid var(--border, #313244)",width:"90vw",maxWidth:1e3,height:"85vh",display:"flex",flexDirection:"column",overflow:"hidden",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.5)"},header:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 20px",borderBottom:"1px solid var(--border, #313244)",background:"var(--surface-1, #181825)"},headerTitle:{fontSize:16,fontWeight:600,color:"var(--text-primary, #cdd6f4)",display:"flex",alignItems:"center",gap:8},closeBtn:{background:"none",border:"none",color:"var(--text-secondary, #a6adc8)",fontSize:20,cursor:"pointer",padding:"4px 8px",borderRadius:6,lineHeight:1},tabs:{display:"flex",borderBottom:"1px solid var(--border, #313244)",background:"var(--surface-1, #181825)",overflowX:"auto",scrollbarWidth:"none"},tab:n=>({padding:"10px 16px",background:"none",border:"none",borderBottom:n?"2px solid var(--accent, #89b4fa)":"2px solid transparent",color:n?"var(--accent, #89b4fa)":"var(--text-secondary, #a6adc8)",fontSize:13,fontWeight:n?600:400,cursor:"pointer",display:"flex",alignItems:"center",gap:6,whiteSpace:"nowrap",transition:"color 0.15s, border-color 0.15s",flexShrink:0}),filters:{display:"flex",gap:8,alignItems:"center",padding:"10px 20px",borderBottom:"1px solid var(--border, #313244)",flexWrap:"wrap"},timeBtn:{border:"1px solid #45475a",borderRadius:4,padding:"4px 8px",fontSize:10,fontWeight:600,cursor:"pointer"},searchInput:{background:"#313244",border:"1px solid #45475a",borderRadius:6,padding:"5px 10px",color:"#cdd6f4",fontSize:12,flex:1,minWidth:120,outline:"none"},refreshBtn:{background:"transparent",border:"1px solid #45475a",borderRadius:6,padding:"5px 12px",color:"#a6adc8",fontSize:11,cursor:"pointer"},content:{flex:1,overflow:"auto",padding:"0 20px"},eventRow:{padding:"8px 12px",borderBottom:"1px solid #313244",cursor:"pointer",transition:"background 0.1s"},tag:{fontSize:10,fontWeight:600,padding:"2px 6px",borderRadius:4,whiteSpace:"nowrap"},detail:{marginTop:8,padding:10,background:"#181825",borderRadius:6,fontSize:11,fontFamily:"monospace",color:"#a6adc8",overflow:"auto",maxHeight:300,whiteSpace:"pre-wrap",wordBreak:"break-all"},footer:{padding:"8px 20px",borderTop:"1px solid #313244"},section:{marginBottom:24},sectionTitle:{color:"#a6adc8",fontSize:12,fontWeight:600,textTransform:"uppercase",letterSpacing:1,marginBottom:12,margin:0},grid:{display:"grid",gridTemplateColumns:"repeat(3, 1fr)",gap:12},card:{background:"#313244",borderRadius:8,padding:"16px 14px",textAlign:"center"},integrationRow:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"8px 12px",background:"#313244",borderRadius:6},statusBadge:{fontSize:10,fontWeight:600,padding:"3px 8px",borderRadius:4}};export{Z as MonitoringModal};