@jefuriiij/synthra 0.1.25 → 0.2.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/CHANGELOG.md +465 -426
- package/LICENSE +21 -21
- package/README.md +222 -222
- package/dist/cli/index.js +726 -285
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/index.js +14 -3
- package/dist/dashboard/index.js.map +1 -1
- package/dist/server/index.js +446 -66
- package/dist/server/index.js.map +1 -1
- package/package.json +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,426 +1,465 @@
|
|
|
1
|
-
# Synthra changelog
|
|
2
|
-
|
|
3
|
-
Notable changes per version. This file ships inside the npm tarball — `syn .`
|
|
4
|
-
reads it after an auto-update to show you what changed.
|
|
5
|
-
|
|
6
|
-
For older versions, see [GitHub Releases](https://github.com/jefuriiij/synthra/releases).
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## [0.
|
|
11
|
-
|
|
12
|
-
###
|
|
13
|
-
|
|
14
|
-
- **
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- **
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
`
|
|
115
|
-
|
|
116
|
-
`
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
###
|
|
170
|
-
|
|
171
|
-
- **
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
- **
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
- **
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
1
|
+
# Synthra changelog
|
|
2
|
+
|
|
3
|
+
Notable changes per version. This file ships inside the npm tarball — `syn .`
|
|
4
|
+
reads it after an auto-update to show you what changed.
|
|
5
|
+
|
|
6
|
+
For older versions, see [GitHub Releases](https://github.com/jefuriiij/synthra/releases).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [0.2.0] — 2026-06-06
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Cross-session "second brain" — a resume digest at session start.** Synthra
|
|
15
|
+
now captures a snapshot at session end (open next-steps/decisions, files
|
|
16
|
+
touched, and commits since your last session) and, on the next session, leads
|
|
17
|
+
the SessionStart primer with a budget-bounded **"Since you were last here"**
|
|
18
|
+
digest. A fresh session arrives already oriented instead of re-paying tokens
|
|
19
|
+
to rediscover recent work. The snapshot lives in `.synthra-graph/`
|
|
20
|
+
(machine-local) and falls back to the normal primer when there's nothing to
|
|
21
|
+
show.
|
|
22
|
+
- **Usage learning — retrieval that gets smarter the more you use it.** Files
|
|
23
|
+
you actually open (`graph_read`) or edit (`graph_register_edit`) accrue a
|
|
24
|
+
time-decayed weight (7-day half-life), and retrieval gives genuinely "hot"
|
|
25
|
+
files a small, capped re-rank boost. It's anchored to files that already match
|
|
26
|
+
your query and capped below the existing seed boost, so it sharpens ranking
|
|
27
|
+
without ever overriding relevance. Purely local, per-developer; degrades to
|
|
28
|
+
the exact prior ranking when there's no usage history. Tunable via
|
|
29
|
+
`SYN_LEARN_HALFLIFE_DAYS` and `SYN_LEARN_BOOST_CAP`.
|
|
30
|
+
- **CLAUDE.md policy v6** — teaches the assistant to trust the resume digest and
|
|
31
|
+
pull concrete next steps via `context_recall({kind:"next"})` instead of
|
|
32
|
+
re-exploring the codebase.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- **`pre-compact.sh` now parses the primer with `jq`, not a greedy `sed`
|
|
37
|
+
capture** — completing the `jq` migration across all four bash hooks (matches
|
|
38
|
+
the Stop/Prime/PreToolUse fixes). The multi-line resume digest contains quotes
|
|
39
|
+
and newlines the old `sed` capture would have mangled.
|
|
40
|
+
|
|
41
|
+
### Internal
|
|
42
|
+
|
|
43
|
+
- **CI (GitHub Actions), Biome (lint + format), and coverage** added. CI runs on
|
|
44
|
+
an ubuntu + windows matrix, so cross-platform hook regressions are caught
|
|
45
|
+
automatically. `.gitattributes` enforces LF line endings on every platform.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## [0.1.25] — 2026-06-06
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **PreToolUse (Moat) bash hook now parses the gate response with `jq`, not a
|
|
54
|
+
greedy `sed` capture (issue #13).** `src/hooks/scripts/pre-tool-use.sh`
|
|
55
|
+
extracted the block `reason` via `sed -n 's/.*"reason"…\(.*\)".*/\1/p'`. The
|
|
56
|
+
greedy `\(.*\)"` capture over-ran into the trailing JSON fields, and because a
|
|
57
|
+
block `reason` legitimately contains double quotes (it quotes the searched
|
|
58
|
+
query, e.g. `"login"`), the captured text broke the deny JSON when embedded
|
|
59
|
+
raw in the output heredoc — so on a real block Claude Code received malformed
|
|
60
|
+
`hookSpecificOutput` and the deny was silently dropped. The hook now reads
|
|
61
|
+
`.decision` / `.reason` with `jq -r '… // empty'` and re-emits the deny object
|
|
62
|
+
with `jq -nc --arg` (correct escaping), behind a `command -v jq` guard that
|
|
63
|
+
silently no-ops when `jq` is absent — mirroring the Stop/Prime hooks fixed in
|
|
64
|
+
#1. Gate/Moat decision logic is unchanged. This completes the `jq` migration
|
|
65
|
+
across all three bash hooks (the last v0.2 item). Verified end-to-end under
|
|
66
|
+
bash on Linux: SessionStart primer injection, Grep/Glob Moat blocks with
|
|
67
|
+
well-formed escaped deny JSON, and Stop-hook token totals reaching the
|
|
68
|
+
dashboard.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## [0.1.24] — 2026-06-06
|
|
73
|
+
|
|
74
|
+
### Added
|
|
75
|
+
|
|
76
|
+
- **`syn doctor [path]` — setup and environment health check (issue #9).** New
|
|
77
|
+
read-only CLI subcommand that runs a one-shot checklist and exits. Checks: Node
|
|
78
|
+
version, `jq` availability (bash Stop/Prime hooks silently no-op without it),
|
|
79
|
+
`claude` CLI on PATH, graph freshness (symbol count, schema version, scan age),
|
|
80
|
+
`.mcp.json` project-scope registration (required for Synthra tools to appear in
|
|
81
|
+
the Claude Code IDE), CLAUDE.md policy-block version, and hook installation
|
|
82
|
+
status. Warnings surface with the exact `syn .` command needed to resolve them.
|
|
83
|
+
The command mutates nothing — safe to run at any time.
|
|
84
|
+
|
|
85
|
+
- **Graph-tool usage metric on the dashboard (issue #2).** The MCP server now
|
|
86
|
+
appends a record to `.synthra-graph/tool_log.jsonl` on every Synthra tool call
|
|
87
|
+
(`graph_continue`, `graph_read`, `graph_register_edit`, etc.). `delta.ts`
|
|
88
|
+
aggregates per-tool call counts into `ProjectStats.tool_calls` (per-project) and
|
|
89
|
+
`global.tool_calls` (cross-project totals). The dashboard shows a new "Graph
|
|
90
|
+
tools used" card in the right column with per-tool counts. This is a positive
|
|
91
|
+
signal complementing the Moat's blocked-Grep count: it captures Synthra pivots
|
|
92
|
+
that happen before a Grep fires, which the block counter misses entirely.
|
|
93
|
+
|
|
94
|
+
- **Session-aware routing — `graph_continue` seeds retrieval with the session's
|
|
95
|
+
touched files (issue #14).** Files the human recently saved (last 15 min) and
|
|
96
|
+
files the AI registered via `graph_register_edit` now get a ranking boost in
|
|
97
|
+
`graph_continue` results, so the returned context tracks what you're actually
|
|
98
|
+
working on. Mirrors the `/pack` route, which already seeded retrieval this way.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## [0.1.23] — 2026-06-06
|
|
103
|
+
|
|
104
|
+
### Added
|
|
105
|
+
|
|
106
|
+
- **Dashboard token-log dedupe can now be disabled via `SYN_DASHBOARD_DEDUPE=0`.**
|
|
107
|
+
By default, `delta.ts` deduplicates `token_log.jsonl` entries that share the
|
|
108
|
+
same project, usage totals, and second-rounded timestamp — collapsing the
|
|
109
|
+
duplicate writes that a co-installed AI tool's Stop hook may produce. Set
|
|
110
|
+
`SYN_DASHBOARD_DEDUPE=0` (also accepts `off` or `false`) to see every raw
|
|
111
|
+
entry. Useful when debugging multi-tool coexistence or auditing raw log data.
|
|
112
|
+
|
|
113
|
+
- **Graph schema-migration check on load.** A new `SCHEMA_VERSION` constant is
|
|
114
|
+
exported from `src/graph/types.ts` and stamped into `info_graph.json` by
|
|
115
|
+
`buildGraph`. On server start, `http.ts` compares the stored graph's
|
|
116
|
+
`schema_version` to the current constant; if they differ it triggers an
|
|
117
|
+
automatic one-time rescan instead of serving an incompatible graph. No
|
|
118
|
+
behavior change today — all graphs are v1 and schema_version matches — but
|
|
119
|
+
this is the forward-safety mechanism for future schema bumps so existing
|
|
120
|
+
graphs are never silently misread.
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
|
|
124
|
+
- **JS/TS parser now captures member-assigned functions** (`exports.handler = fn`,
|
|
125
|
+
`module.exports.route = () => {}`, `this.x = () => {}`). Previously these
|
|
126
|
+
CommonJS/member-export patterns were invisible to the query, so modules that
|
|
127
|
+
exclusively use this style extracted zero symbols and degraded to whole-file
|
|
128
|
+
reads via `graph_read`. A member-assignment capture has been added to both
|
|
129
|
+
`JS_QUERY` and `TS_QUERY` in `src/scanner/parsers/typescript.ts`. Note: a
|
|
130
|
+
pure-wiring `server.js` whose only structure is anonymous inline-callback
|
|
131
|
+
arguments (e.g. `io.use(...)` / `socket.on(event, fn)`) is genuinely
|
|
132
|
+
symbol-less — that is correct, and the gate's symbol-hit guard already
|
|
133
|
+
prevents blocking such files.
|
|
134
|
+
|
|
135
|
+
### Changed
|
|
136
|
+
|
|
137
|
+
- **Policy block v4 → v5.** Adds a "large file — pull the symbol, don't
|
|
138
|
+
chunk" nudge to address recurring dogfood friction: on large files Claude
|
|
139
|
+
was reading successive line-range chunks instead of fetching the specific
|
|
140
|
+
symbol via `graph_read("file::symbol")`. The v5 block now explicitly
|
|
141
|
+
instructs: when a file is large, use `graph_read("file/path.ts::SymbolName")`
|
|
142
|
+
to pull the symbol directly rather than reading successive line-range chunks.
|
|
143
|
+
`POLICY_VERSION` bumped `4 → 5`; existing v4 blocks auto-upgrade on the
|
|
144
|
+
next `syn .` run.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## [0.1.22] — 2026-06-06
|
|
149
|
+
|
|
150
|
+
### Fixed
|
|
151
|
+
|
|
152
|
+
- **`graph_read` now resolves shortened file paths (path-suffix fallback).** Previously
|
|
153
|
+
`graph_read` performed an exact `path === target` match only. Passing a shortened path
|
|
154
|
+
like `appsettings.json` returned "file not found" even when
|
|
155
|
+
`connectwarev2/.../appsettings.json` was indexed. A new `resolveFileTarget` helper (now
|
|
156
|
+
exported) tries an exact match first; on a miss it looks for a unique path-suffix match
|
|
157
|
+
and serves that file; if multiple files share the suffix it reports them as ambiguous with
|
|
158
|
+
candidate paths rather than guessing. Symbol lookups use the resolved path. No API or
|
|
159
|
+
protocol change. Roadmap item #11.
|
|
160
|
+
|
|
161
|
+
- **Gate content-keyword relaxation now intersects file contents, not just file paths.**
|
|
162
|
+
The Moat's recent-activity relaxation previously matched query tokens against the paths of
|
|
163
|
+
recently-touched files only. A query like `Grep "login"` would not relax on a recent save
|
|
164
|
+
of `auth.ts` unless the word "login" appeared in the path. Now the relaxation also checks
|
|
165
|
+
the recently-touched file's graph-node keywords (its indexed content), so a recent save
|
|
166
|
+
relaxes a Grep whenever the file *contains* the queried term — not just when the path
|
|
167
|
+
matches it. Completes roadmap item #3.
|
|
168
|
+
|
|
169
|
+
### Changed
|
|
170
|
+
|
|
171
|
+
- **Dashboard Projects card shows a first-run hint in the empty state.** When no projects
|
|
172
|
+
have run `syn .` yet, the Projects card now displays "No projects yet — run `syn .` in a
|
|
173
|
+
project to start" instead of a blank card. The Recent-turns card already carried this
|
|
174
|
+
hint; Projects now matches it. Roadmap item #10.
|
|
175
|
+
|
|
176
|
+
- **`bin` path normalization (chore).** Ran `npm pkg fix` to normalize `bin` entries from
|
|
177
|
+
`./bin/syn` to `bin/syn`. Silences the cosmetic publish warnings
|
|
178
|
+
(`"bin[syn]" script name was cleaned`). `syn` and `synthra` still resolve to the same
|
|
179
|
+
entry point. Roadmap item #4.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## [0.1.21] — 2026-06-06
|
|
184
|
+
|
|
185
|
+
### Added
|
|
186
|
+
|
|
187
|
+
- **HubL (HubSpot CMS) symbol extraction for `.html` and `.hubl` files.**
|
|
188
|
+
Previously `.html` files were content-indexed only — keyword search and
|
|
189
|
+
whole-file reads, no symbol-level granularity. On HubSpot projects this
|
|
190
|
+
meant the graph contributed nothing: zero `graph_continue`/`graph_read`
|
|
191
|
+
calls resolved to symbol slices all session. Now `.html` and `.hubl` files
|
|
192
|
+
run through a new **regex-based** parser (`parsers/hubl.ts`; there is no
|
|
193
|
+
tree-sitter grammar for HubL):
|
|
194
|
+
- `{% macro name(args) %}` → extracted as a `function` symbol
|
|
195
|
+
- `{% block name %}` → extracted as a `component` symbol
|
|
196
|
+
- `{% include / extends / import / from "path" %}` → import edges (relative
|
|
197
|
+
paths resolve to local templates; `.html`/`.hubl` added to the resolver's
|
|
198
|
+
extension list)
|
|
199
|
+
|
|
200
|
+
Plain HTML with no HubL tags is unaffected — the parser yields zero symbols
|
|
201
|
+
and zero imports, identical to before. No API, protocol, or policy-block
|
|
202
|
+
change. Roadmap item #12.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## [0.1.20] — 2026-06-06
|
|
207
|
+
|
|
208
|
+
### Fixed
|
|
209
|
+
|
|
210
|
+
- **Gate (Moat) no longer blocks Grep/Glob queries the graph cannot answer with a symbol.**
|
|
211
|
+
Previously, the PreToolUse gate blocked whenever retrieval confidence was `medium` or `high`,
|
|
212
|
+
but confidence is driven by keyword and path hits too — not only by symbol matches. This meant
|
|
213
|
+
literal/attribute/CSS-selector patterns (`data-tour=`, `class=`, `: 100%`, `.filter-bar`,
|
|
214
|
+
`<div>`) and path-only Globs were blocked and redirected to `graph_read`, which has no symbol
|
|
215
|
+
slice to return for those queries, so Claude fell back to Grep or a whole-file Read anyway —
|
|
216
|
+
a wasted round-trip. Found across multiple dogfood sessions including well-indexed Svelte
|
|
217
|
+
repos. Two new guards close the gap:
|
|
218
|
+
- **Query-shape pre-filter** — Grep patterns that target markup, CSS, attributes, or string
|
|
219
|
+
literals are allowed through up front, before the retrieval step runs.
|
|
220
|
+
- **Symbol-hit requirement** — the gate now only blocks when retrieval matched a symbol whose
|
|
221
|
+
name the query mentions exactly. `RetrievalResult` gained a `symbolMatched` flag; the scorer
|
|
222
|
+
exposes `exactSym`.
|
|
223
|
+
|
|
224
|
+
Net effect: genuine symbol lookups still block (verified: `fetchWith429Retry`,
|
|
225
|
+
`MAX_ROWS_PER_TABLE`, `verifyPin`, `SOCKET_AUTH_SECRET`, `seedCredentials`); queries that
|
|
226
|
+
could never have been answered by the graph now allow through without the wasted redirect.
|
|
227
|
+
No API, protocol, or policy-block change — purely server-side gate behavior.
|
|
228
|
+
|
|
229
|
+
- **Gate and rank test coverage added** (`tests/gate.test.ts`, `tests/rank.test.ts`).
|
|
230
|
+
Chips at the v0.2 backlog item to fill vitest tests beyond `it.todo` placeholders.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## [0.1.19] — 2026-06-01
|
|
235
|
+
|
|
236
|
+
### Changed
|
|
237
|
+
|
|
238
|
+
- **Policy block v4: targeted Read-before-Edit for graph-discovered files.**
|
|
239
|
+
Claude Code's `Edit` tool requires a file to have been opened with its own
|
|
240
|
+
`Read` tool; a `graph_read` slice does not satisfy that gate. Previously,
|
|
241
|
+
editing a file known only through `graph_read` would fail with *"File has
|
|
242
|
+
not been read yet"* and force a whole-file `Read` — eroding token savings on
|
|
243
|
+
edit-heavy sessions. The v4 policy now instructs: take the line range already
|
|
244
|
+
reported in the `graph_read` header (e.g. `…::handler (L120-168)`), do a
|
|
245
|
+
targeted `Read` with matching `offset`/`limit`, then `Edit`. This satisfies
|
|
246
|
+
the gate while keeping the read small. Existing v3 blocks auto-upgrade on the
|
|
247
|
+
next `syn .` run.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## [0.1.18] — 2026-06-01
|
|
252
|
+
|
|
253
|
+
### Fixed
|
|
254
|
+
|
|
255
|
+
- **Stop hook on Linux/macOS no longer posts zero tokens to the dashboard.** The bash
|
|
256
|
+
`stop.sh` hook extracted `transcript_path` from the Claude Code Stop payload using a
|
|
257
|
+
greedy `sed` capture (`\(.*\)"`). Because the real payload has additional fields after
|
|
258
|
+
`transcript_path`, the capture grabbed those trailing fields and produced a
|
|
259
|
+
non-existent path string. The `-f` file check therefore always failed, totals were
|
|
260
|
+
never POSTed to `/log`, and the dashboard stayed stuck at 0 on every turn (GitHub
|
|
261
|
+
issue #1). Fixed by parsing with `jq -r '.transcript_path // empty'` and moving the
|
|
262
|
+
`command -v jq` guard above the parse so the hook exits cleanly when `jq` is absent.
|
|
263
|
+
- **SessionStart/PreCompact primer hook (`prime.sh`) hardened the same way.** The
|
|
264
|
+
`/prime` response is `{"primer":"…","port":…}`, so the old greedy capture accidentally
|
|
265
|
+
injected trailing `","port":…` junk into the primer string. Because primer text can
|
|
266
|
+
contain inner quotes, a negated-class fix (`[^"]*`) would have truncated it at the
|
|
267
|
+
first quote — `jq -r '.primer // empty'` is the correct parse. Switched `printf '%b'`
|
|
268
|
+
to `printf '%s'` since `jq -r` already decodes JSON escapes.
|
|
269
|
+
- Both fixes are **bash-only**. The Windows PowerShell hooks (`stop.ps1`, `prime.ps1`)
|
|
270
|
+
use `ConvertFrom-Json` and were already correct.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## [0.1.17] — 2026-05-29
|
|
275
|
+
|
|
276
|
+
### Added
|
|
277
|
+
|
|
278
|
+
- **`syn .` scaffolds an agent-onboarding CLAUDE.md on brand-new projects.**
|
|
279
|
+
When a project has no CLAUDE.md, Synthra now writes a lean skeleton —
|
|
280
|
+
`Build & test`, `Conventions`, `Key decisions`, `Gotchas` (with TODO
|
|
281
|
+
prompts) — *above* its managed policy block, instead of a bare policy
|
|
282
|
+
block. This is the durable "why/how" layer the graph can't infer; the
|
|
283
|
+
graph still owns "what/where." Fill it in, or run `/init` to auto-draft.
|
|
284
|
+
The skeleton is written **once** and lives outside the
|
|
285
|
+
`<!-- synthra-policy -->` markers, so re-running `syn .` (which
|
|
286
|
+
refreshes the policy block) never clobbers what you've written.
|
|
287
|
+
Projects that already have a CLAUDE.md are untouched — no skeleton is
|
|
288
|
+
injected.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## [0.1.16] — 2026-05-29
|
|
293
|
+
|
|
294
|
+
### Changed
|
|
295
|
+
|
|
296
|
+
- **Moat card shows 50 recent gate decisions** (was 12). The inline list
|
|
297
|
+
already scrolls within the card, and the `/data` payload already carries
|
|
298
|
+
up to 500 gates, so this just renders more of them. The headline block
|
|
299
|
+
count was always all-time/uncapped — unchanged.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## [0.1.15] — 2026-05-29
|
|
304
|
+
|
|
305
|
+
### Changed
|
|
306
|
+
|
|
307
|
+
- **Recent turns are paginated.** The dashboard now carries up to 500 turns
|
|
308
|
+
(was 25) and shows them 25 per page with Prev/Next controls — so you can
|
|
309
|
+
browse history instead of only seeing the last 25. Configurable via
|
|
310
|
+
`SYN_DASHBOARD_RECENT_N` (default 500).
|
|
311
|
+
- **Model-usage donut is now all-time, not last-25.** It was tallying models
|
|
312
|
+
from the capped recent-turns window, so a run of >25 same-model turns showed
|
|
313
|
+
that model at 100% and hid the rest. It now sums the uncapped per-project
|
|
314
|
+
model counts, so it always reflects your true all-time split.
|
|
315
|
+
- **Dashboard poll slowed 2s → 10s.** Lighter on resources and steadier to
|
|
316
|
+
read; pagination stays live (the current page re-renders each poll).
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## [0.1.14] — 2026-05-29
|
|
321
|
+
|
|
322
|
+
### Changed
|
|
323
|
+
|
|
324
|
+
- **Dashboard visual refresh.** No API surface change — all visual / UX.
|
|
325
|
+
- Removed the hero strip and the standalone Legend card. Date + active
|
|
326
|
+
project now live as compact chips inside the top nav (active-project
|
|
327
|
+
path uses RTL truncation so the folder name stays visible).
|
|
328
|
+
- New **Projects bar chart** in the left column — colored bars ranked
|
|
329
|
+
by turn count. Stable per-name OKLCH palette (8 colors, hash-keyed)
|
|
330
|
+
so a project keeps the same color across sessions. Click any row to
|
|
331
|
+
open its full breakdown.
|
|
332
|
+
- **Donut legend** gains a turn-count column alongside the percentage.
|
|
333
|
+
- **Savings card** elevated: radial green backdrop, money figure 40px,
|
|
334
|
+
soft glow — makes the "what Synthra saved you" number the visual
|
|
335
|
+
anchor of the dashboard.
|
|
336
|
+
- **Recent turns column headers** are now hover-explainable.
|
|
337
|
+
- Active-project chip tightens + month name hides under 1100px width.
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## [0.1.13] — 2026-05-29
|
|
342
|
+
|
|
343
|
+
### Fixed
|
|
344
|
+
|
|
345
|
+
- **Dashboard footer version is now dynamic.** Was hardcoded to `v0.1.8`
|
|
346
|
+
in the HTML and never updated. The dashboard server now injects the
|
|
347
|
+
running binary's version (from `package.json`) into the footer on every
|
|
348
|
+
`GET /` via a `__SYN_VERSION__` placeholder. Re-run `syn .` after an
|
|
349
|
+
update and the dashboard reflects the new version automatically.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## [0.1.12] — 2026-05-29
|
|
354
|
+
|
|
355
|
+
### Fixed
|
|
356
|
+
|
|
357
|
+
- **`Language.query is deprecated` spam at scan time.** Every parsed file
|
|
358
|
+
printed the warning — 57 prints on a Flutter codebase, one per parsed
|
|
359
|
+
file. Switched all four parsers (TypeScript, JavaScript, Python, Dart,
|
|
360
|
+
plus the generic helper) from the deprecated `language.query(QUERY)`
|
|
361
|
+
to `new Query(language, QUERY)`. No behavior change, just clean
|
|
362
|
+
terminal output.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## [0.1.11] — 2026-05-29
|
|
367
|
+
|
|
368
|
+
### Fixed
|
|
369
|
+
|
|
370
|
+
- **Dart parser actually runs now.** Was silently broken since v0.1 due to an
|
|
371
|
+
ABI mismatch (shipped wasm was ABI v15, pinned `web-tree-sitter` only
|
|
372
|
+
supported v13–v14). Every `.dart` file got zero symbols, zero imports —
|
|
373
|
+
the exception was swallowed by the parser's try/catch. Bumped
|
|
374
|
+
`web-tree-sitter` to `^0.25.10` to fix.
|
|
375
|
+
- **Real Dart symbol extraction.** Classes, mixins, extensions, enums,
|
|
376
|
+
typedefs, top-level functions, methods, getters, setters, constructors.
|
|
377
|
+
- **Dart import normalization.** `package:foo/bar.dart` and `dart:async` are
|
|
378
|
+
stripped (cross-project); bare `'sibling.dart'` is rewritten to
|
|
379
|
+
`./sibling.dart` so the project resolver can complete them.
|
|
380
|
+
|
|
381
|
+
### Changed
|
|
382
|
+
|
|
383
|
+
- **Update check runs on every `syn .`** (no more 24h cache). If you're on
|
|
384
|
+
latest, stays silent. If outdated, prompts `[y/N]` as before.
|
|
385
|
+
- **Auto-update now shows a changelog.** After `npm install -g …@latest`
|
|
386
|
+
succeeds, Synthra prints the new version's section from this file before
|
|
387
|
+
telling you to re-run. Catches `npm install` outside of `syn .` too —
|
|
388
|
+
next startup compares your current version to `~/.synthra/last-seen-version.json`
|
|
389
|
+
and prints if it's newer.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## [0.1.10] — 2026-05-29
|
|
394
|
+
|
|
395
|
+
### Changed
|
|
396
|
+
|
|
397
|
+
- **CLAUDE.md policy v2 → v3.** Session-end now goes through
|
|
398
|
+
`context_remember({kind: "task"|"decision"|"next"})` instead of writing
|
|
399
|
+
`.synthra/CONTEXT.md` directly. The Stop hook always re-rendered CONTEXT.md
|
|
400
|
+
from `context-store.json` — under v2 Claude's direct writes were getting
|
|
401
|
+
wiped on session end. Existing v2 blocks auto-upgrade.
|
|
402
|
+
|
|
403
|
+
### Added
|
|
404
|
+
|
|
405
|
+
- **Scanner ignores more build caches.** `.dart_tool/`, `.flutter-plugins`,
|
|
406
|
+
`.flutter-plugins-dependencies`, `.gradle/`, `target/`, `Pods/`,
|
|
407
|
+
`DerivedData/`, `__pycache__/`, `.venv/`, `venv/`, `.tox/`,
|
|
408
|
+
`.pytest_cache/`, `.mypy_cache/`, `.ruff_cache/`, `obj/`, `.vs/`.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## [0.1.9] — 2026-05-29
|
|
413
|
+
|
|
414
|
+
### Fixed
|
|
415
|
+
|
|
416
|
+
- **Crash on prototype-colliding symbol names.** `buildSymbolIndex` built
|
|
417
|
+
the lookup on a plain `{}`, so a symbol named `toString` (which every
|
|
418
|
+
Dart class overrides), `constructor`, `valueOf`, etc. resolved to the
|
|
419
|
+
inherited `Object.prototype` member and crashed on `.push`. Now uses
|
|
420
|
+
`Object.create(null)` on both fresh-build and load-from-disk paths.
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## [0.1.8] — 2026-05-29
|
|
425
|
+
|
|
426
|
+
### Added
|
|
427
|
+
|
|
428
|
+
- **Interactive auto-update.** `syn .` checks npm at startup; if a newer
|
|
429
|
+
version is available, prompts `[y/N]`. On `y`, runs
|
|
430
|
+
`npm install -g @jefuriiij/synthra@latest` with stdio inherited and
|
|
431
|
+
exits with re-run instructions. Non-TTY runs (CI, piped stdin) fall
|
|
432
|
+
back to a silent one-line hint. `SYN_NO_UPDATE_CHECK=1` opts out.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## [0.1.7] — 2026-05-29
|
|
437
|
+
|
|
438
|
+
### Fixed
|
|
439
|
+
|
|
440
|
+
- **JS parser missed CommonJS imports + JS class names.** Unified TS/JS
|
|
441
|
+
query only matched ES `import_statement`, and used `(type_identifier)`
|
|
442
|
+
for class names — which is TS-grammar-only. Result: every `.js`/`.cjs`/
|
|
443
|
+
`.mjs` file silently produced zero imports, and any class in a JS file
|
|
444
|
+
was skipped. Split into `TS_QUERY` and `JS_QUERY`; JS query adds a
|
|
445
|
+
`require()` capture and uses `(identifier)` for class names.
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## [0.1.6] — 2026-05-29
|
|
450
|
+
|
|
451
|
+
### Fixed
|
|
452
|
+
|
|
453
|
+
- **MCP registration now uses `--scope project`** so the Claude Code IDE
|
|
454
|
+
extension actually sees Synthra. The previous `--scope local` wrote to
|
|
455
|
+
a per-project section of `~/.claude.json` that only the `claude` CLI
|
|
456
|
+
reads — invisible to the IDE.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## [0.1.5] and earlier
|
|
461
|
+
|
|
462
|
+
See [GitHub commits](https://github.com/jefuriiij/synthra/commits/main) for
|
|
463
|
+
detail. v0.1.5 introduced the v2 policy template with namespace + skip rules;
|
|
464
|
+
v0.1.4 fixed a DEP0190 deprecation on Windows; v0.1.3 was the dashboard
|
|
465
|
+
redesign (Cool Marine palette, FAQ modal, savings audit row).
|