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.
- package/dist/assets/{BossLogsModal-2lqGyuCD.js → BossLogsModal-B_dgVF7L.js} +1 -1
- package/dist/assets/{BossSpawnModal-CR-ofDeB.js → BossSpawnModal-CSO1bYxA.js} +1 -1
- package/dist/assets/{ControlsModal-DQ8QVshA.js → ControlsModal-WMTTqbca.js} +1 -1
- package/dist/assets/{DockerLogsModal-D6yQTHy7.js → DockerLogsModal-THzhLHch.js} +1 -1
- package/dist/assets/{EmbeddedEditor-wechGxGl.js → EmbeddedEditor-DWLKJYav.js} +1 -1
- package/dist/assets/GmailOAuthSetup-DN9ceaS6.js +270 -0
- package/dist/assets/{GoogleOAuthSetup-BcpJEydM.js → GoogleOAuthSetup-bVST2EOB.js} +1 -1
- package/dist/assets/{IframeModal-E2E7NR08.js → IframeModal-BELsjvgi.js} +1 -1
- package/dist/assets/{IntegrationsPanel-CrS2QOFR.js → IntegrationsPanel-DwDr4BRt.js} +2 -2
- package/dist/assets/{LogViewerModal-BpIPZeFr.js → LogViewerModal-CMe04PO5.js} +1 -1
- package/dist/assets/MonitoringModal-CqSalNeY.js +1 -0
- package/dist/assets/{PM2LogsModal-CDk_2mi1.js → PM2LogsModal-CCmCDxVt.js} +1 -1
- package/dist/assets/{RestoreArchivedAreaModal-BmgBrk9J.js → RestoreArchivedAreaModal-IfzPidIv.js} +1 -1
- package/dist/assets/{SaveSnapshotModal-DWta9pcx.js → SaveSnapshotModal-DUhrVD5l.js} +1 -1
- package/dist/assets/{Scene2DCanvas-C3CcFsjU.js → Scene2DCanvas-Bl5DUC7w.js} +1 -1
- package/dist/assets/{SceneManager-mFUakRNl.js → SceneManager-BGO9tiaI.js} +1 -1
- package/dist/assets/{SkillsPanel-Br3h8GNh.js → SkillsPanel-CPFOI4Tl.js} +1 -1
- package/dist/assets/{SnapshotManager-CPYWfnPR.js → SnapshotManager-Cbu0tJBz.js} +1 -1
- package/dist/assets/{SpawnModal-DSDirR0j.js → SpawnModal-BqDbsYLY.js} +1 -1
- package/dist/assets/{SubordinateAssignmentModal-Daz67phV.js → SubordinateAssignmentModal-DOqkhL_L.js} +1 -1
- package/dist/assets/{SupervisorPanel-DoAl5e8W.js → SupervisorPanel-BvX-dlk_.js} +1 -1
- package/dist/assets/{TriggerManagerPanel-CVIHbqDt.js → TriggerManagerPanel-RUVFmKmf.js} +1 -1
- package/dist/assets/WorkflowEditorPanel-CwZpEqzM.js +42 -0
- package/dist/assets/browser-ponyfill-DZOWXZ4K.js +2 -0
- package/dist/assets/camera-D_KeL_pz.js +1 -0
- package/dist/assets/{index-I-I3pPPW.js → index-B-wV06cR.js} +1 -1
- package/dist/assets/index-BFguOWBW.js +2 -0
- package/dist/assets/{index-uXOqPsuU.js → index-C7gqY2AA.js} +1 -1
- package/dist/assets/{index-CE_GbjZ6.js → index-CiD1Rwaq.js} +1 -1
- package/dist/assets/index-D4nfDvz4.js +49 -0
- package/dist/assets/{index-CvMf5n2v.js → index-DDPUtz8-.js} +1 -1
- package/dist/assets/{index-Chrxgrys.js → index-EH8IBvSU.js} +1 -1
- package/dist/assets/{index-DWVQ48nQ.js → index-H0PzHVFw.js} +1 -1
- package/dist/assets/main-Cjm0d8dZ.js +152 -0
- package/dist/assets/main-DqC9_fF4.css +1 -0
- package/dist/assets/{prism-cpp-CcQnz8LL.js → prism-cpp-CK2Ly5dS.js} +1 -1
- package/dist/assets/{prism-csharp-DFIAaw4Y.js → prism-csharp-ByDDDiWW.js} +1 -1
- package/dist/assets/{prism-elixir-jP4m4T-8.js → prism-elixir-df27OMMQ.js} +1 -1
- package/dist/assets/{prism-haskell-BrMZM7_F.js → prism-haskell-Ce8aBmia.js} +1 -1
- package/dist/assets/{prism-java-BEsh8u4L.js → prism-java-CK6tws4L.js} +1 -1
- package/dist/assets/{prism-perl-ecHKp0bZ.js → prism-perl-UZfqnD51.js} +1 -1
- package/dist/assets/{prism-php-Ch-kk89U.js → prism-php-Dt9698bA.js} +1 -1
- package/dist/assets/{prism-ruby-zNpGDk6v.js → prism-ruby-CQBUuZIF.js} +1 -1
- package/dist/assets/{prism-scss-BeuXx0O0.js → prism-scss-CeN16CFC.js} +1 -1
- package/dist/assets/{vendor-react-uS-d4TUT.js → vendor-react--Eh9ivFN.js} +2 -2
- package/dist/assets/{web-IWJRtE3-.js → web-D1vWYL8u.js} +1 -1
- package/dist/assets/{web-DdRt5c0R.js → web-DUq3Undh.js} +1 -1
- package/dist/index.html +3 -3
- package/dist/src/packages/server/data/builtin-skills/boss-instructions.js +57 -66
- package/dist/src/packages/server/data/builtin-skills/index.js +2 -0
- package/dist/src/packages/server/data/builtin-skills/workflow-builder.js +253 -0
- package/dist/src/packages/server/data/builtin-skills/workflow-designer.js +157 -0
- package/dist/src/packages/server/data/event-queries.js +24 -0
- package/dist/src/packages/server/data/migrations/002_workflow_agent_binding.sql +14 -0
- package/dist/src/packages/server/data/migrations/003_matcher_executions.sql +19 -0
- package/dist/src/packages/server/data/migrations/004_matcher_message_source.sql +8 -0
- package/dist/src/packages/server/integrations/gmail/gmail-client.js +75 -15
- package/dist/src/packages/server/integrations/gmail/gmail-config.js +32 -2
- package/dist/src/packages/server/integrations/gmail/gmail-routes.js +5 -0
- package/dist/src/packages/server/integrations/gmail/index.js +23 -1
- package/dist/src/packages/server/integrations/jira/jira-client.js +11 -5
- package/dist/src/packages/server/integrations/jira/jira-routes.js +20 -3
- package/dist/src/packages/server/integrations/jira/jira-skill.js +110 -58
- package/dist/src/packages/server/routes/trigger-routes.js +22 -0
- package/dist/src/packages/server/routes/workflow-routes.js +86 -2
- package/dist/src/packages/server/services/boss-message-service.js +1 -1
- package/dist/src/packages/server/services/llm-matcher-service.js +50 -81
- package/dist/src/packages/server/services/trigger-service.js +195 -6
- package/dist/src/packages/server/services/workflow-executor.js +230 -0
- package/dist/src/packages/server/services/workflow-service.js +59 -13
- package/package.json +7 -7
- package/dist/assets/GmailOAuthSetup-B2GDjROU.js +0 -222
- package/dist/assets/MonitoringModal-CIF9MUm9.js +0 -1
- package/dist/assets/WorkflowEditorPanel-C4BRfmDM.js +0 -42
- package/dist/assets/browser-ponyfill-DIm4hKhx.js +0 -2
- package/dist/assets/camera-8crtHeRa.js +0 -1
- package/dist/assets/index--PCy0J0f.js +0 -49
- package/dist/assets/index-DOzx4Y9b.js +0 -2
- package/dist/assets/main-DQpuQfqS.css +0 -1
- 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
|
-
|
|
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.
|
|
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.
|
|
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": "^
|
|
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": "^
|
|
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": "^
|
|
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.
|
|
103
|
+
"tar": "7.5.13"
|
|
104
104
|
},
|
|
105
105
|
"devDependencies": {
|
|
106
106
|
"@capacitor/android": "^8.1.0",
|
|
107
|
-
"@capacitor/cli": "^
|
|
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};
|