flecto 1.0.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/LICENSE +21 -0
- package/README.md +342 -0
- package/index.js +403 -0
- package/package.json +53 -0
- package/src/alerter.js +252 -0
- package/src/config.js +107 -0
- package/src/differ.js +277 -0
- package/src/envelope.js +47 -0
- package/src/parser.js +77 -0
- package/src/policy.js +65 -0
- package/src/renderer.js +134 -0
- package/src/watcher.js +137 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Siddharth Mehta
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Flecto
|
|
2
|
+
|
|
3
|
+
A semantic file watcher that detects *meaningful* changes in structured config files and reports them in plain English — not raw line diffs.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
[10:42:31] config/prod.yaml — 3 changes
|
|
7
|
+
~ database.pool_size: 5 → 20
|
|
8
|
+
+ feature_flags.dark_mode: true
|
|
9
|
+
- deprecated.old_key
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Supports **JSON**, **YAML**, **TOML**, and **ENV** files.
|
|
13
|
+
|
|
14
|
+
Recruiter-focused overview: see `README_RECRUITERS.md`.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g flecto
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or from source:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git clone https://github.com/siddharrth2005/sentinel.git
|
|
28
|
+
cd sentinel
|
|
29
|
+
npm install
|
|
30
|
+
npm install -g .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
After install, `flecto` is available globally.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
### Watch a file
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
flecto watch config/prod.yaml
|
|
43
|
+
flecto watch .env
|
|
44
|
+
flecto watch settings.json
|
|
45
|
+
flecto watch pyproject.toml
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Watch multiple files/globs
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
flecto watch "config/**/*.yaml" ".env"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Watch with verbose output
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
flecto watch config/prod.yaml --mode verbose
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Verbose mode shows before/after values on separate lines and adds a blank line between change events.
|
|
61
|
+
|
|
62
|
+
### Ignore specific key paths
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
flecto watch config/prod.yaml --ignore "updated_at,meta.timestamp"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Comma-separated paths. Supports:
|
|
69
|
+
- exact path ignore: `meta.timestamp`
|
|
70
|
+
- subtree ignore: `meta` (ignores `meta.*` and `meta[0].*`)
|
|
71
|
+
- wildcard segment: `servers[*].meta.timestamp`
|
|
72
|
+
- key anywhere: `**.updated_at`
|
|
73
|
+
|
|
74
|
+
### Run a shell command on every change
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
flecto watch .env --command "docker-compose restart app"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Changes are passed to the command as JSON in the `FLECTO_CHANGES` environment variable, and the watched file path in `FLECTO_FILE`.
|
|
81
|
+
|
|
82
|
+
If the change payload is too large for env vars, Flecto writes it to `FLECTO_CHANGES_FILE` and sets `FLECTO_CHANGES` to `[]`.
|
|
83
|
+
|
|
84
|
+
### POST changes to a webhook
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
flecto watch config/prod.yaml --webhook https://hooks.example.com/notify
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Add custom headers (repeatable):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
flecto watch config/prod.yaml \
|
|
94
|
+
--webhook https://hooks.example.com/notify \
|
|
95
|
+
--webhook-header "Authorization: Bearer TOKEN"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Flecto webhook payloads include an event envelope with:
|
|
99
|
+
- `schema_version`
|
|
100
|
+
- `event_id`
|
|
101
|
+
- `batch_id`
|
|
102
|
+
- `event_type` (`changes` or `lifecycle`)
|
|
103
|
+
- `source`
|
|
104
|
+
- `emitted_at`
|
|
105
|
+
- `file`
|
|
106
|
+
- `changes`
|
|
107
|
+
|
|
108
|
+
Payload shape:
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"schema_version": "1.1",
|
|
112
|
+
"event_id": "uuid",
|
|
113
|
+
"batch_id": "uuid",
|
|
114
|
+
"event_type": "changes",
|
|
115
|
+
"source": "watch",
|
|
116
|
+
"emitted_at": "2026-04-14T10:42:31.000Z",
|
|
117
|
+
"file": "/absolute/path/to/config/prod.yaml",
|
|
118
|
+
"changes": [
|
|
119
|
+
{ "type": "changed", "path": "database.pool_size", "before": 5, "after": 20 }
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Combine command + webhook
|
|
125
|
+
|
|
126
|
+
Both can be active at the same time:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
flecto watch .env \
|
|
130
|
+
--command "make reload" \
|
|
131
|
+
--webhook https://hooks.example.com/notify
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Delivery semantics and failure policy
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
flecto watch config/prod.yaml \
|
|
138
|
+
--webhook https://hooks.example.com/notify \
|
|
139
|
+
--delivery-mode at-least-once \
|
|
140
|
+
--on-alert-failure retry
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- `--delivery-mode best-effort` (default): no persistent retries
|
|
144
|
+
- `--delivery-mode at-least-once`: failed webhook events are persisted and retried
|
|
145
|
+
- `--on-alert-failure warn|exit|retry`: controls behavior when command/webhook fails
|
|
146
|
+
|
|
147
|
+
### Polling interval
|
|
148
|
+
|
|
149
|
+
For network drives or editors that write via temp files, tune the polling interval:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
flecto watch config/prod.yaml --polling --interval 500
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Default polling interval is `100ms` (polling is **off** unless you pass `--polling`).
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## CI mode
|
|
160
|
+
|
|
161
|
+
Run semantic diffs in CI against snapshots or git refs:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
flecto ci "config/**/*.yaml" \
|
|
165
|
+
--snapshot-ref HEAD~1 \
|
|
166
|
+
--format github-annotations \
|
|
167
|
+
--fail-on "changed,policy,error"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`--format` supports:
|
|
171
|
+
- `json`
|
|
172
|
+
- `ndjson`
|
|
173
|
+
- `github-annotations`
|
|
174
|
+
|
|
175
|
+
`--fail-on` supports:
|
|
176
|
+
- `changed`
|
|
177
|
+
- `added`
|
|
178
|
+
- `removed`
|
|
179
|
+
- `policy`
|
|
180
|
+
- `error`
|
|
181
|
+
- `warn`
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Snapshot & diff mode
|
|
186
|
+
|
|
187
|
+
### Save a baseline snapshot
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
flecto watch config/prod.yaml --snapshot
|
|
191
|
+
# → .flecto-snapshots/<id>.json
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Diff the current file against the saved snapshot
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
flecto watch config/prod.yaml --diff
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Prints all changes since the snapshot was taken. Exits with:
|
|
201
|
+
- **code 0** — file is clean (no changes)
|
|
202
|
+
- **code 1** — changes detected (useful in CI pipelines)
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Output format
|
|
207
|
+
|
|
208
|
+
### Compact (default)
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
[HH:MM:SS] <filepath> — N changes
|
|
212
|
+
~ <path>: <before> → <after>
|
|
213
|
+
+ <path>: <value>
|
|
214
|
+
- <path>: <value>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
- `~` (yellow) — value changed
|
|
218
|
+
- `+` (green) — key added
|
|
219
|
+
- `-` (red) — key removed
|
|
220
|
+
|
|
221
|
+
### Verbose (`--mode verbose`)
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
[HH:MM:SS] <filepath> — N changes
|
|
225
|
+
~ <path>
|
|
226
|
+
before: <value>
|
|
227
|
+
after: <value>
|
|
228
|
+
+ <path>: <value>
|
|
229
|
+
(key added)
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Change event shape
|
|
236
|
+
|
|
237
|
+
Each semantic change is represented as:
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
{
|
|
241
|
+
type: 'added' | 'removed' | 'changed',
|
|
242
|
+
path: string, // dot-notation key path, e.g. "database.pool_size"
|
|
243
|
+
before?: unknown, // previous value (absent for 'added')
|
|
244
|
+
after?: unknown, // new value (absent for 'removed')
|
|
245
|
+
note?: string, // optional note, e.g. "type changed from string to number"
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Array items use index notation: `servers[1].port`.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Policy checks
|
|
254
|
+
|
|
255
|
+
Built-in policy findings are evaluated from semantic changes:
|
|
256
|
+
- secret-looking keys changed (`secret`, `token`, `password`, `api_key`, etc.)
|
|
257
|
+
- dangerous toggles enabled (`debug`, `allow_insecure`, `disable_tls`, `skip_tls_verify`)
|
|
258
|
+
- large `pool_size` jumps (>=2x)
|
|
259
|
+
|
|
260
|
+
Policy findings can trigger CI failures with `--fail-on policy,error`.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Error handling
|
|
265
|
+
|
|
266
|
+
| Situation | Behavior |
|
|
267
|
+
|---|---|
|
|
268
|
+
| File not found | Error message + exit 1 |
|
|
269
|
+
| Unsupported format | Lists supported extensions + exit 1 |
|
|
270
|
+
| Parse error during watch | Warning shown, last valid state kept, watching continues |
|
|
271
|
+
| Command failure | Warning shown, watcher continues |
|
|
272
|
+
| Webhook failure | Warning shown, watcher continues |
|
|
273
|
+
| Ctrl+C | Clean shutdown message |
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## .flectorc configuration
|
|
278
|
+
|
|
279
|
+
Use `.flectorc`, `.flectorc.json`, `.flectorc.yaml`, or `.flectorc.yml`.
|
|
280
|
+
Bootstrap one with:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
flecto init
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"defaults": {
|
|
291
|
+
"mode": "compact",
|
|
292
|
+
"interval": 100,
|
|
293
|
+
"ignore": ["**.updated_at"],
|
|
294
|
+
"deliveryMode": "best-effort",
|
|
295
|
+
"onAlertFailure": "warn"
|
|
296
|
+
},
|
|
297
|
+
"profiles": {
|
|
298
|
+
"dev": { "mode": "verbose" },
|
|
299
|
+
"ci": { "failOn": "policy,error" }
|
|
300
|
+
},
|
|
301
|
+
"files": ["config/**/*.yaml", ".env"],
|
|
302
|
+
"exclude": ["**/node_modules/**"]
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
CLI flags take precedence over profile/default values.
|
|
307
|
+
|
|
308
|
+
Use a profile with:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
flecto watch --profile dev
|
|
312
|
+
flecto ci --profile ci
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Check setup with:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
flecto doctor
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Running tests
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
npm test
|
|
327
|
+
# or directly:
|
|
328
|
+
node --test test/*.test.js
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Tests cover differ, watcher behavior, alert webhook delivery, policy logic, and CI command behavior.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## How it works
|
|
336
|
+
|
|
337
|
+
1. **Parser** — detects format by file extension and parses the file into JS values.
|
|
338
|
+
2. **Watcher** — uses [chokidar](https://github.com/paulmillr/chokidar) with debouncing and lifecycle events.
|
|
339
|
+
3. **Differ** — computes semantic changes (supports object/array/scalar roots, ignore rules).
|
|
340
|
+
4. **Policy engine** — derives severity findings from change patterns.
|
|
341
|
+
5. **Envelope** — wraps change batches in a versioned automation event schema.
|
|
342
|
+
6. **Alerter** — runs commands and/or webhook delivery with configurable retry semantics.
|