@fractary/faber-mcp 1.1.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/README.md +523 -0
- package/dist/backends/local-files.d.ts +89 -0
- package/dist/backends/local-files.d.ts.map +1 -0
- package/dist/backends/local-files.js +538 -0
- package/dist/backends/local-files.js.map +1 -0
- package/dist/backends/s3-archive.d.ts +74 -0
- package/dist/backends/s3-archive.d.ts.map +1 -0
- package/dist/backends/s3-archive.js +341 -0
- package/dist/backends/s3-archive.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/runs.d.ts +36 -0
- package/dist/resources/runs.d.ts.map +1 -0
- package/dist/resources/runs.js +91 -0
- package/dist/resources/runs.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +130 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/events.d.ts +30 -0
- package/dist/tools/events.d.ts.map +1 -0
- package/dist/tools/events.js +199 -0
- package/dist/tools/events.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +8 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/workflow.d.ts +28 -0
- package/dist/tools/workflow.d.ts.map +1 -0
- package/dist/tools/workflow.js +282 -0
- package/dist/tools/workflow.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +62 -0
- package/dist/types.js.map +1 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
# FABER MCP Server
|
|
2
|
+
|
|
3
|
+
A unified MCP (Model Context Protocol) server that provides complete FABER workflow orchestration and event logging capabilities. This server exposes 10 MCP tools for workflow control, state management, and event tracking, enabling AI agents to interact with the FABER workflow framework.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### Workflow Orchestration (6 Tools)
|
|
8
|
+
- **workflow_run**: Execute complete FABER workflows (Frame → Architect → Build → Evaluate → Release)
|
|
9
|
+
- **workflow_status**: Query workflow progress and current state
|
|
10
|
+
- **workflow_resume**: Resume paused workflows from where they left off
|
|
11
|
+
- **workflow_pause**: Pause running workflows for later resumption
|
|
12
|
+
- **workflow_recover**: Recover failed workflows from checkpoints or specific phases
|
|
13
|
+
- **workflow_cleanup**: Clean up old completed/failed workflow state files
|
|
14
|
+
|
|
15
|
+
### Event Logging (4 Tools)
|
|
16
|
+
- **event_emit**: Log workflow events with rich metadata, artifacts, and error tracking
|
|
17
|
+
- **run_get**: Retrieve run details and current state
|
|
18
|
+
- **run_list**: Query and list workflow runs with filtering
|
|
19
|
+
- **events_consolidate**: Export events to JSONL format for archival or analysis
|
|
20
|
+
|
|
21
|
+
### MCP Resources
|
|
22
|
+
- `faber://runs` - List all workflow runs
|
|
23
|
+
- `faber://runs/{run_id}` - Get run details
|
|
24
|
+
- `faber://runs/{run_id}/events` - Get run event log
|
|
25
|
+
|
|
26
|
+
## Prerequisites
|
|
27
|
+
|
|
28
|
+
- Node.js >= 18.0.0
|
|
29
|
+
- npm or yarn
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
### From Workspace (Development)
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# From repository root
|
|
37
|
+
npm install
|
|
38
|
+
npm run build -w mcp/server
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### From npm (Production)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @fractary/faber-mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
The server uses environment variables for configuration:
|
|
50
|
+
|
|
51
|
+
| Variable | Default | Description |
|
|
52
|
+
|----------|---------|-------------|
|
|
53
|
+
| `FABER_RUNS_PATH` | `.fractary/plugins/faber/runs` | Base path for run storage |
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Starting the Server
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Production (requires build)
|
|
61
|
+
npm start
|
|
62
|
+
|
|
63
|
+
# Development (with tsx)
|
|
64
|
+
npm run dev
|
|
65
|
+
|
|
66
|
+
# From workspace
|
|
67
|
+
npm run start -w mcp/server
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The server communicates via stdio, making it suitable for integration with MCP clients.
|
|
71
|
+
|
|
72
|
+
### MCP Client Configuration
|
|
73
|
+
|
|
74
|
+
Add to your MCP client configuration (e.g., `~/.config/claude/mcp.json`):
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"fractary-faber": {
|
|
80
|
+
"command": "node",
|
|
81
|
+
"args": ["/path/to/faber/mcp/server/dist/server.js"],
|
|
82
|
+
"env": {
|
|
83
|
+
"FABER_RUNS_PATH": ".fractary/plugins/faber/runs"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Using the Binary
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"mcpServers": {
|
|
95
|
+
"fractary-faber": {
|
|
96
|
+
"command": "fractary-faber-mcp",
|
|
97
|
+
"env": {
|
|
98
|
+
"FABER_RUNS_PATH": ".fractary/plugins/faber/runs"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Tools Reference
|
|
106
|
+
|
|
107
|
+
### Workflow Tools
|
|
108
|
+
|
|
109
|
+
#### fractary_faber_workflow_run
|
|
110
|
+
|
|
111
|
+
Run a complete FABER workflow for a work item.
|
|
112
|
+
|
|
113
|
+
**Parameters:**
|
|
114
|
+
| Name | Type | Required | Default | Description |
|
|
115
|
+
|------|------|----------|---------|-------------|
|
|
116
|
+
| `work_id` | string | Yes | - | Work item ID to process (e.g., "123" for issue #123) |
|
|
117
|
+
| `autonomy` | string | No | "assisted" | Autonomy level: dry-run, assisted, guarded, autonomous |
|
|
118
|
+
| `config` | object | No | - | Optional workflow configuration overrides |
|
|
119
|
+
|
|
120
|
+
**Example:**
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"work_id": "123",
|
|
124
|
+
"autonomy": "assisted",
|
|
125
|
+
"config": {
|
|
126
|
+
"phases": {
|
|
127
|
+
"build": {
|
|
128
|
+
"skip_tests": false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### fractary_faber_workflow_status
|
|
136
|
+
|
|
137
|
+
Get workflow status and progress.
|
|
138
|
+
|
|
139
|
+
**Parameters:**
|
|
140
|
+
| Name | Type | Required | Description |
|
|
141
|
+
|------|------|----------|-------------|
|
|
142
|
+
| `workflow_id` | string | No* | Workflow ID to check (e.g., "WF-abc123") |
|
|
143
|
+
| `work_id` | string | No* | Work item ID to find active workflow for |
|
|
144
|
+
|
|
145
|
+
*At least one of `workflow_id` or `work_id` must be provided.
|
|
146
|
+
|
|
147
|
+
**Example:**
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"work_id": "123"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### fractary_faber_workflow_resume
|
|
155
|
+
|
|
156
|
+
Resume a paused workflow.
|
|
157
|
+
|
|
158
|
+
**Parameters:**
|
|
159
|
+
| Name | Type | Required | Description |
|
|
160
|
+
|------|------|----------|-------------|
|
|
161
|
+
| `workflow_id` | string | Yes | Workflow ID to resume |
|
|
162
|
+
|
|
163
|
+
**Example:**
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"workflow_id": "WF-abc123"
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### fractary_faber_workflow_pause
|
|
171
|
+
|
|
172
|
+
Pause a running workflow.
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
| Name | Type | Required | Description |
|
|
176
|
+
|------|------|----------|-------------|
|
|
177
|
+
| `workflow_id` | string | Yes | Workflow ID to pause |
|
|
178
|
+
|
|
179
|
+
**Example:**
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"workflow_id": "WF-abc123"
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### fractary_faber_workflow_recover
|
|
187
|
+
|
|
188
|
+
Recover a failed workflow from a checkpoint or specific phase.
|
|
189
|
+
|
|
190
|
+
**Parameters:**
|
|
191
|
+
| Name | Type | Required | Description |
|
|
192
|
+
|------|------|----------|-------------|
|
|
193
|
+
| `workflow_id` | string | Yes | Workflow ID to recover |
|
|
194
|
+
| `checkpoint_id` | string | No | Optional checkpoint ID to recover from |
|
|
195
|
+
| `from_phase` | string | No | Optional phase to restart from (frame, architect, build, evaluate, release) |
|
|
196
|
+
| `skip_phases` | array | No | Phases to skip during recovery |
|
|
197
|
+
|
|
198
|
+
**Example:**
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"workflow_id": "WF-abc123",
|
|
202
|
+
"from_phase": "build"
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### fractary_faber_workflow_cleanup
|
|
207
|
+
|
|
208
|
+
Clean up old completed/failed workflow state files.
|
|
209
|
+
|
|
210
|
+
**Parameters:**
|
|
211
|
+
| Name | Type | Required | Default | Description |
|
|
212
|
+
|------|------|----------|---------|-------------|
|
|
213
|
+
| `max_age_days` | number | No | 30 | Delete workflows older than this many days |
|
|
214
|
+
|
|
215
|
+
**Example:**
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"max_age_days": 60
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Event Tools
|
|
223
|
+
|
|
224
|
+
#### fractary_faber_event_emit
|
|
225
|
+
|
|
226
|
+
Emit a workflow event to a FABER run.
|
|
227
|
+
|
|
228
|
+
**Parameters:**
|
|
229
|
+
| Name | Type | Required | Description |
|
|
230
|
+
|------|------|----------|-------------|
|
|
231
|
+
| `run_id` | string | Yes | Full run identifier (org/project/uuid) |
|
|
232
|
+
| `type` | string | Yes | Event type (see Event Types below) |
|
|
233
|
+
| `phase` | string | No | Current workflow phase |
|
|
234
|
+
| `step` | string | No | Current step within phase |
|
|
235
|
+
| `status` | string | No | Event status (started, completed, failed, skipped) |
|
|
236
|
+
| `message` | string | No | Human-readable description |
|
|
237
|
+
| `metadata` | object | No | Additional structured metadata |
|
|
238
|
+
| `artifacts` | array | No | Artifact references |
|
|
239
|
+
| `error` | object | No | Error details if status is "failed" |
|
|
240
|
+
| `agent_id` | string | No | Agent that emitted the event |
|
|
241
|
+
|
|
242
|
+
**Example:**
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"run_id": "fractary/faber/550e8400-e29b-41d4-a716-446655440000",
|
|
246
|
+
"type": "phase_started",
|
|
247
|
+
"phase": "build",
|
|
248
|
+
"status": "started",
|
|
249
|
+
"message": "Starting build phase"
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### fractary_faber_run_get
|
|
254
|
+
|
|
255
|
+
Retrieve run details and current state.
|
|
256
|
+
|
|
257
|
+
**Parameters:**
|
|
258
|
+
| Name | Type | Required | Default | Description |
|
|
259
|
+
|------|------|----------|---------|-------------|
|
|
260
|
+
| `run_id` | string | Yes | - | Full run identifier |
|
|
261
|
+
| `include_events` | boolean | No | false | Include event log in response |
|
|
262
|
+
|
|
263
|
+
**Example:**
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"run_id": "fractary/faber/550e8400-e29b-41d4-a716-446655440000",
|
|
267
|
+
"include_events": true
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### fractary_faber_run_list
|
|
272
|
+
|
|
273
|
+
Query and list workflow runs.
|
|
274
|
+
|
|
275
|
+
**Parameters:**
|
|
276
|
+
| Name | Type | Required | Default | Description |
|
|
277
|
+
|------|------|----------|---------|-------------|
|
|
278
|
+
| `limit` | number | No | 50 | Maximum number of runs to return |
|
|
279
|
+
| `status` | string | No | - | Filter by run status |
|
|
280
|
+
| `work_id` | string | No | - | Filter by work item ID |
|
|
281
|
+
| `since` | string | No | - | Filter runs created after this ISO timestamp |
|
|
282
|
+
|
|
283
|
+
**Example:**
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"limit": 10,
|
|
287
|
+
"status": "running"
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### fractary_faber_events_consolidate
|
|
292
|
+
|
|
293
|
+
Export events to JSONL format.
|
|
294
|
+
|
|
295
|
+
**Parameters:**
|
|
296
|
+
| Name | Type | Required | Description |
|
|
297
|
+
|------|------|----------|-------------|
|
|
298
|
+
| `run_id` | string | Yes | Full run identifier |
|
|
299
|
+
| `output_path` | string | No | Optional output file path (defaults to run directory) |
|
|
300
|
+
|
|
301
|
+
**Example:**
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"run_id": "fractary/faber/550e8400-e29b-41d4-a716-446655440000"
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Event Types
|
|
309
|
+
|
|
310
|
+
The following event types are supported:
|
|
311
|
+
|
|
312
|
+
### Workflow Control
|
|
313
|
+
- `workflow_started` - Workflow execution began
|
|
314
|
+
- `workflow_completed` - Workflow finished successfully
|
|
315
|
+
- `workflow_failed` - Workflow terminated with error
|
|
316
|
+
- `workflow_paused` - Workflow paused by user
|
|
317
|
+
- `workflow_resumed` - Workflow resumed from pause
|
|
318
|
+
|
|
319
|
+
### Phase Events
|
|
320
|
+
- `phase_started` - FABER phase began (frame, architect, build, evaluate, release)
|
|
321
|
+
- `phase_completed` - Phase finished successfully
|
|
322
|
+
- `phase_failed` - Phase terminated with error
|
|
323
|
+
- `phase_skipped` - Phase skipped due to configuration
|
|
324
|
+
|
|
325
|
+
### Step Events
|
|
326
|
+
- `step_started` - Individual step began
|
|
327
|
+
- `step_completed` - Step finished successfully
|
|
328
|
+
- `step_failed` - Step terminated with error
|
|
329
|
+
|
|
330
|
+
### Integration Events
|
|
331
|
+
- `work_created` - Work item created in tracker
|
|
332
|
+
- `work_updated` - Work item updated
|
|
333
|
+
- `branch_created` - Git branch created
|
|
334
|
+
- `commit_created` - Git commit created
|
|
335
|
+
- `pr_created` - Pull request created
|
|
336
|
+
- `pr_updated` - Pull request updated
|
|
337
|
+
- `pr_merged` - Pull request merged
|
|
338
|
+
|
|
339
|
+
### Agent Events
|
|
340
|
+
- `agent_started` - AI agent began execution
|
|
341
|
+
- `agent_completed` - Agent finished successfully
|
|
342
|
+
- `agent_failed` - Agent terminated with error
|
|
343
|
+
- `tool_called` - MCP tool invoked
|
|
344
|
+
- `prompt_sent` - Prompt sent to LLM
|
|
345
|
+
- `prompt_received` - Response received from LLM
|
|
346
|
+
|
|
347
|
+
### Artifact Events
|
|
348
|
+
- `artifact_created` - File or output artifact created
|
|
349
|
+
- `artifact_updated` - Artifact modified
|
|
350
|
+
- `spec_created` - Specification document created
|
|
351
|
+
- `spec_updated` - Specification modified
|
|
352
|
+
|
|
353
|
+
### Error Events
|
|
354
|
+
- `error` - General error occurred
|
|
355
|
+
- `validation_failed` - Input validation failed
|
|
356
|
+
- `timeout` - Operation timed out
|
|
357
|
+
- `retry` - Operation being retried
|
|
358
|
+
|
|
359
|
+
## Data Structure
|
|
360
|
+
|
|
361
|
+
### Run State
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
interface RunState {
|
|
365
|
+
run_id: string; // org/project/uuid
|
|
366
|
+
work_id: string; // Work item ID
|
|
367
|
+
status: "pending" | "running" | "completed" | "failed" | "paused";
|
|
368
|
+
start_time: string; // ISO timestamp
|
|
369
|
+
end_time?: string; // ISO timestamp
|
|
370
|
+
current_phase?: string; // frame, architect, build, evaluate, release
|
|
371
|
+
metadata: {
|
|
372
|
+
project: string;
|
|
373
|
+
organization: string;
|
|
374
|
+
workflow_type: string;
|
|
375
|
+
autonomy: string;
|
|
376
|
+
};
|
|
377
|
+
artifacts?: Array<{
|
|
378
|
+
type: string;
|
|
379
|
+
path: string;
|
|
380
|
+
created_at: string;
|
|
381
|
+
}>;
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Event Structure
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
interface FaberEvent {
|
|
389
|
+
event_id: string; // Monotonic integer
|
|
390
|
+
run_id: string; // org/project/uuid
|
|
391
|
+
timestamp: string; // ISO timestamp
|
|
392
|
+
type: string; // Event type (see Event Types)
|
|
393
|
+
phase?: string; // Workflow phase
|
|
394
|
+
step?: string; // Step within phase
|
|
395
|
+
status?: string; // started, completed, failed, skipped
|
|
396
|
+
message?: string; // Human-readable description
|
|
397
|
+
metadata?: Record<string, unknown>;
|
|
398
|
+
artifacts?: Array<{
|
|
399
|
+
type: string;
|
|
400
|
+
path: string;
|
|
401
|
+
}>;
|
|
402
|
+
error?: {
|
|
403
|
+
code: string;
|
|
404
|
+
message: string;
|
|
405
|
+
stack?: string;
|
|
406
|
+
};
|
|
407
|
+
agent_id?: string; // Agent identifier
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Migration from Event Gateway
|
|
412
|
+
|
|
413
|
+
If you're migrating from `@fractary/faber-event-gateway`, note the following changes:
|
|
414
|
+
|
|
415
|
+
### Tool Name Changes
|
|
416
|
+
|
|
417
|
+
| Old Name | New Name |
|
|
418
|
+
|----------|----------|
|
|
419
|
+
| `emit_event` | `fractary_faber_event_emit` |
|
|
420
|
+
| `get_run` | `fractary_faber_run_get` |
|
|
421
|
+
| `list_runs` | `fractary_faber_run_list` |
|
|
422
|
+
| `consolidate_events` | `fractary_faber_events_consolidate` |
|
|
423
|
+
|
|
424
|
+
### Package Name
|
|
425
|
+
|
|
426
|
+
- Old: `@fractary/faber-event-gateway`
|
|
427
|
+
- New: `@fractary/faber-mcp`
|
|
428
|
+
|
|
429
|
+
### Server Name
|
|
430
|
+
|
|
431
|
+
- Old: `faber-event-gateway`
|
|
432
|
+
- New: `fractary-faber`
|
|
433
|
+
|
|
434
|
+
### Behavior Changes
|
|
435
|
+
|
|
436
|
+
- All existing event tools retain the same functionality
|
|
437
|
+
- 6 new workflow orchestration tools added
|
|
438
|
+
- Resource URIs unchanged: `faber://runs/*`
|
|
439
|
+
|
|
440
|
+
## Development
|
|
441
|
+
|
|
442
|
+
### Build
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
npm run build
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Watch Mode
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
npm run watch
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Type Checking
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
npm run typecheck
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Testing
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
npm test
|
|
464
|
+
npm run test:watch
|
|
465
|
+
npm run test:coverage
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Linting
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
npm run lint
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Architecture
|
|
475
|
+
|
|
476
|
+
```
|
|
477
|
+
┌─────────────────────────────────────┐
|
|
478
|
+
│ MCP Client (Claude Code, etc) │
|
|
479
|
+
└─────────────────────────────────────┘
|
|
480
|
+
│
|
|
481
|
+
│ MCP Protocol (stdio)
|
|
482
|
+
▼
|
|
483
|
+
┌─────────────────────────────────────┐
|
|
484
|
+
│ @fractary/faber-mcp │
|
|
485
|
+
│ ┌────────────┬─────────────────┐ │
|
|
486
|
+
│ │ workflow.ts│ events.ts │ │
|
|
487
|
+
│ │ (6 tools) │ (4 tools) │ │
|
|
488
|
+
│ └────────────┴─────────────────┘ │
|
|
489
|
+
│ ┌─────────────────────────────┐ │
|
|
490
|
+
│ │ backends/local-files.ts │ │
|
|
491
|
+
│ │ (atomic operations) │ │
|
|
492
|
+
│ └─────────────────────────────┘ │
|
|
493
|
+
└─────────────────────────────────────┘
|
|
494
|
+
│
|
|
495
|
+
│ SDK imports
|
|
496
|
+
▼
|
|
497
|
+
┌─────────────────────────────────────┐
|
|
498
|
+
│ @fractary/faber SDK │
|
|
499
|
+
│ FaberWorkflow │ StateManager │
|
|
500
|
+
└─────────────────────────────────────┘
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## Concurrency Safety
|
|
504
|
+
|
|
505
|
+
The MCP server implements atomic operations for event ID generation to prevent race conditions when multiple agents emit events concurrently. This is achieved through:
|
|
506
|
+
|
|
507
|
+
1. **Atomic File Operations**: Event IDs are generated using atomic file reads with retry logic
|
|
508
|
+
2. **Directory-Level Locking**: State updates use temporary files with atomic renames
|
|
509
|
+
3. **Safe Metadata Updates**: Run metadata is updated via atomic read-modify-write cycles
|
|
510
|
+
|
|
511
|
+
## License
|
|
512
|
+
|
|
513
|
+
MIT
|
|
514
|
+
|
|
515
|
+
## Contributing
|
|
516
|
+
|
|
517
|
+
See the main [FABER repository](https://github.com/fractary/faber) for contribution guidelines.
|
|
518
|
+
|
|
519
|
+
## Support
|
|
520
|
+
|
|
521
|
+
- **Issues**: https://github.com/fractary/faber/issues
|
|
522
|
+
- **Documentation**: https://fractary.dev/docs/faber
|
|
523
|
+
- **MCP Protocol**: https://spec.modelcontextprotocol.io
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Files Backend for FABER Event Gateway
|
|
3
|
+
*
|
|
4
|
+
* Stores events as individual JSON files in the run's events directory.
|
|
5
|
+
* Uses atomic file operations for concurrent access safety.
|
|
6
|
+
*/
|
|
7
|
+
import { ConsolidateResult, EmitEventResult, FaberEvent, GetRunResult, ListRunsResult } from "../types.js";
|
|
8
|
+
export declare class LocalFilesBackend {
|
|
9
|
+
private readonly basePath;
|
|
10
|
+
private readonly resolvedBasePath;
|
|
11
|
+
constructor(basePath: string);
|
|
12
|
+
/**
|
|
13
|
+
* Validate run_id format - strict validation to prevent edge cases
|
|
14
|
+
* - org and project must start and end with alphanumeric
|
|
15
|
+
* - uuid must be valid format
|
|
16
|
+
*/
|
|
17
|
+
private validateRunId;
|
|
18
|
+
/**
|
|
19
|
+
* Get the directory path for a run with path traversal protection
|
|
20
|
+
*/
|
|
21
|
+
private getRunDir;
|
|
22
|
+
/**
|
|
23
|
+
* Get the events directory for a run
|
|
24
|
+
*/
|
|
25
|
+
private getEventsDir;
|
|
26
|
+
/**
|
|
27
|
+
* Generate ISO timestamp with milliseconds for consistency
|
|
28
|
+
*/
|
|
29
|
+
private getTimestamp;
|
|
30
|
+
/**
|
|
31
|
+
* Sleep helper for retry backoff
|
|
32
|
+
*/
|
|
33
|
+
private sleep;
|
|
34
|
+
/**
|
|
35
|
+
* Get next event ID atomically using atomic rename pattern
|
|
36
|
+
*
|
|
37
|
+
* This approach is more reliable than file locking:
|
|
38
|
+
* 1. Read current ID
|
|
39
|
+
* 2. Write new ID to temp file with random suffix
|
|
40
|
+
* 3. Atomically rename temp file to target
|
|
41
|
+
* 4. If rename fails due to race, retry with exponential backoff
|
|
42
|
+
*/
|
|
43
|
+
private getNextEventId;
|
|
44
|
+
/**
|
|
45
|
+
* Update state.json atomically - CRITICAL operation
|
|
46
|
+
* Throws on failure to ensure state consistency
|
|
47
|
+
*/
|
|
48
|
+
private updateState;
|
|
49
|
+
/**
|
|
50
|
+
* Emit a workflow event
|
|
51
|
+
*/
|
|
52
|
+
emitEvent(eventData: Partial<FaberEvent>): Promise<EmitEventResult>;
|
|
53
|
+
/**
|
|
54
|
+
* Get run state and metadata
|
|
55
|
+
*/
|
|
56
|
+
getRun(runId: string, includeEvents?: boolean): Promise<GetRunResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Get events for a run with streaming support for large event sets
|
|
59
|
+
* Uses a generator pattern to avoid loading all events into memory
|
|
60
|
+
*/
|
|
61
|
+
getEventsStream(runId: string): AsyncGenerator<FaberEvent>;
|
|
62
|
+
/**
|
|
63
|
+
* Get all events for a run (for backward compatibility)
|
|
64
|
+
* For large event sets, prefer getEventsStream
|
|
65
|
+
*/
|
|
66
|
+
getEvents(runId: string): Promise<FaberEvent[]>;
|
|
67
|
+
/**
|
|
68
|
+
* List runs with optional filters
|
|
69
|
+
* Uses an index file for performance when available
|
|
70
|
+
*/
|
|
71
|
+
listRuns(filters: {
|
|
72
|
+
work_id?: string;
|
|
73
|
+
status?: string;
|
|
74
|
+
org?: string;
|
|
75
|
+
project?: string;
|
|
76
|
+
limit?: number;
|
|
77
|
+
}): Promise<ListRunsResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Consolidate events to JSONL format using streaming
|
|
80
|
+
* Avoids loading all events into memory
|
|
81
|
+
*/
|
|
82
|
+
consolidateEvents(runId: string): Promise<ConsolidateResult>;
|
|
83
|
+
/**
|
|
84
|
+
* Update the runs index for faster listing
|
|
85
|
+
* Should be called after run completion
|
|
86
|
+
*/
|
|
87
|
+
updateRunsIndex(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=local-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-files.d.ts","sourceRoot":"","sources":["../../src/backends/local-files.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EACL,iBAAiB,EACjB,eAAe,EAGf,UAAU,EACV,YAAY,EACZ,cAAc,EAIf,MAAM,aAAa,CAAC;AAsDrB,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,QAAQ,EAAE,MAAM;IAM5B;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAOrB;;OAEG;IACH,OAAO,CAAC,SAAS;IAYjB;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;;;;;;;OAQG;YACW,cAAc;IAsD5B;;;OAGG;IACH,OAAO,CAAC,WAAW;IAmCnB;;OAEG;IACG,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IAuGzE;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,OAAO,CAAC,YAAY,CAAC;IAwDzE;;;OAGG;IACI,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC;IAgCjE;;;OAGG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAQrD;;;OAGG;IACG,QAAQ,CAAC,OAAO,EAAE;QACtB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,cAAc,CAAC;IAkI3B;;;OAGG;IACG,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAiElE;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAOvC"}
|