@4da/mcp-server 5.0.3 → 6.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/CHANGELOG.md +667 -0
- package/README.md +66 -35
- package/dist/build-staleness.d.ts +35 -0
- package/dist/build-staleness.js +95 -0
- package/dist/db.d.ts +53 -2
- package/dist/db.js +242 -36
- package/dist/doctor.js +27 -7
- package/dist/embeddings.js +7 -1
- package/dist/freshness-markers.d.ts +34 -0
- package/dist/freshness-markers.js +74 -0
- package/dist/gitignore.d.ts +37 -0
- package/dist/gitignore.js +130 -0
- package/dist/index.js +127 -44
- package/dist/live/bun-lockfile.d.ts +26 -0
- package/dist/live/bun-lockfile.js +123 -0
- package/dist/live/cargo-platform.d.ts +38 -0
- package/dist/live/cargo-platform.js +178 -0
- package/dist/live/changelog-classify.d.ts +41 -0
- package/dist/live/changelog-classify.js +207 -0
- package/dist/live/changelog.d.ts +64 -0
- package/dist/live/changelog.js +318 -0
- package/dist/live/crates-registry.js +3 -1
- package/dist/live/crates-versions.d.ts +47 -0
- package/dist/live/crates-versions.js +201 -0
- package/dist/live/dependency-set.d.ts +13 -0
- package/dist/live/dependency-set.js +95 -0
- package/dist/live/dev-scope.d.ts +32 -0
- package/dist/live/dev-scope.js +102 -0
- package/dist/live/file-signature.d.ts +18 -0
- package/dist/live/file-signature.js +43 -0
- package/dist/live/go-registry.js +3 -1
- package/dist/live/hn-fetcher.js +9 -3
- package/dist/live/index.d.ts +105 -2
- package/dist/live/index.js +266 -139
- package/dist/live/install-state.d.ts +43 -0
- package/dist/live/install-state.js +150 -0
- package/dist/live/js-lockfile-readers.d.ts +46 -0
- package/dist/live/js-lockfile-readers.js +181 -0
- package/dist/live/lockfile-parsers-pygo.d.ts +60 -0
- package/dist/live/lockfile-parsers-pygo.js +274 -0
- package/dist/live/lockfile-parsers.d.ts +69 -0
- package/dist/live/lockfile-parsers.js +311 -0
- package/dist/live/lockfile-types.d.ts +34 -0
- package/dist/live/lockfile-types.js +42 -0
- package/dist/live/maintenance.d.ts +33 -0
- package/dist/live/maintenance.js +37 -0
- package/dist/live/npm-packument.d.ts +47 -0
- package/dist/live/npm-packument.js +150 -0
- package/dist/live/npm-registry.js +67 -53
- package/dist/live/osv-scanner.d.ts +31 -1
- package/dist/live/osv-scanner.js +119 -10
- package/dist/live/package-archive.d.ts +49 -0
- package/dist/live/package-archive.js +186 -0
- package/dist/live/pypi-registry.js +3 -1
- package/dist/live/registry-health.d.ts +16 -0
- package/dist/live/registry-health.js +74 -0
- package/dist/live/release-metadata.d.ts +67 -0
- package/dist/live/release-metadata.js +16 -0
- package/dist/live/resolution.d.ts +43 -0
- package/dist/live/resolution.js +62 -0
- package/dist/live/semver-precedence.d.ts +30 -0
- package/dist/live/semver-precedence.js +83 -0
- package/dist/live/severity-scope.d.ts +57 -0
- package/dist/live/severity-scope.js +89 -0
- package/dist/live/types.d.ts +83 -0
- package/dist/live/upgrade-sources.d.ts +71 -0
- package/dist/live/upgrade-sources.js +198 -0
- package/dist/live/version-compare.d.ts +39 -0
- package/dist/live/version-compare.js +130 -0
- package/dist/live/version-resolver.d.ts +14 -1
- package/dist/live/version-resolver.js +93 -303
- package/dist/native-bindings.d.ts +19 -0
- package/dist/native-bindings.js +39 -0
- package/dist/project-manifests.d.ts +40 -0
- package/dist/project-manifests.js +193 -0
- package/dist/project-scanner.js +38 -48
- package/dist/project-tree.d.ts +41 -0
- package/dist/project-tree.js +110 -0
- package/dist/prompts.d.ts +28 -0
- package/dist/prompts.js +54 -0
- package/dist/schema-registry.d.ts +41 -29
- package/dist/schema-registry.js +98 -105
- package/dist/server-instructions.d.ts +11 -0
- package/dist/server-instructions.js +36 -0
- package/dist/tool-args.d.ts +28 -0
- package/dist/tool-args.js +93 -0
- package/dist/tool-dispatch.d.ts +1 -1
- package/dist/tool-dispatch.js +42 -8
- package/dist/tools/app-plan.d.ts +92 -0
- package/dist/tools/app-plan.js +155 -0
- package/dist/tools/briefing-stored-advisories.d.ts +20 -0
- package/dist/tools/briefing-stored-advisories.js +58 -0
- package/dist/tools/briefing-task-scope.d.ts +73 -0
- package/dist/tools/briefing-task-scope.js +197 -0
- package/dist/tools/briefing-wisdom.d.ts +31 -0
- package/dist/tools/briefing-wisdom.js +148 -0
- package/dist/tools/decision-enforcement.d.ts +0 -5
- package/dist/tools/decision-enforcement.js +0 -4
- package/dist/tools/decision-memory.js +18 -66
- package/dist/tools/dependency-check-signals.d.ts +74 -0
- package/dist/tools/dependency-check-signals.js +264 -0
- package/dist/tools/dependency-check.d.ts +98 -0
- package/dist/tools/dependency-check.js +295 -0
- package/dist/tools/dependency-health.js +74 -21
- package/dist/tools/developer-dna.d.ts +3 -0
- package/dist/tools/developer-dna.js +16 -15
- package/dist/tools/ecosystem-pulse.d.ts +6 -2
- package/dist/tools/ecosystem-pulse.js +53 -14
- package/dist/tools/get-actionable-signals.d.ts +26 -4
- package/dist/tools/get-actionable-signals.js +214 -251
- package/dist/tools/get-context.d.ts +2 -0
- package/dist/tools/get-context.js +9 -1
- package/dist/tools/get-relevant-content.d.ts +3 -1
- package/dist/tools/get-relevant-content.js +34 -3
- package/dist/tools/index.d.ts +4 -2
- package/dist/tools/index.js +4 -2
- package/dist/tools/install-drift-notes.d.ts +51 -0
- package/dist/tools/install-drift-notes.js +172 -0
- package/dist/tools/knowledge-gap-citations.d.ts +55 -0
- package/dist/tools/knowledge-gap-citations.js +132 -0
- package/dist/tools/knowledge-gap-exposure.d.ts +72 -0
- package/dist/tools/knowledge-gap-exposure.js +160 -0
- package/dist/tools/knowledge-gap-grading.d.ts +91 -0
- package/dist/tools/knowledge-gap-grading.js +157 -0
- package/dist/tools/knowledge-gap-installs.d.ts +65 -0
- package/dist/tools/knowledge-gap-installs.js +134 -0
- package/dist/tools/knowledge-gap-ranges.d.ts +51 -0
- package/dist/tools/knowledge-gap-ranges.js +146 -0
- package/dist/tools/knowledge-gap-scope.d.ts +63 -0
- package/dist/tools/knowledge-gap-scope.js +118 -0
- package/dist/tools/knowledge-gaps.d.ts +12 -3
- package/dist/tools/knowledge-gaps.js +172 -121
- package/dist/tools/package-presence.d.ts +24 -0
- package/dist/tools/package-presence.js +35 -0
- package/dist/tools/record-feedback.d.ts +0 -1
- package/dist/tools/record-feedback.js +7 -8
- package/dist/tools/signal-classifier.d.ts +25 -0
- package/dist/tools/signal-classifier.js +40 -0
- package/dist/tools/upgrade-impact-callsites.d.ts +52 -0
- package/dist/tools/upgrade-impact-callsites.js +226 -0
- package/dist/tools/upgrade-impact-literals.d.ts +45 -0
- package/dist/tools/upgrade-impact-literals.js +118 -0
- package/dist/tools/upgrade-impact-report.d.ts +80 -0
- package/dist/tools/upgrade-impact-report.js +178 -0
- package/dist/tools/upgrade-impact.d.ts +84 -0
- package/dist/tools/upgrade-impact.js +305 -0
- package/dist/tools/upgrade-planner.d.ts +41 -8
- package/dist/tools/upgrade-planner.js +201 -53
- package/dist/tools/vulnerability-scan-concise.d.ts +72 -0
- package/dist/tools/vulnerability-scan-concise.js +97 -0
- package/dist/tools/vulnerability-scan-format.d.ts +137 -0
- package/dist/tools/vulnerability-scan-format.js +276 -0
- package/dist/tools/vulnerability-scan.d.ts +338 -18
- package/dist/tools/vulnerability-scan.js +84 -125
- package/dist/tools/what-should-i-know.d.ts +86 -19
- package/dist/tools/what-should-i-know.js +277 -283
- package/dist/types.d.ts +4 -1
- package/package.json +27 -30
- package/dist/schemas/agent-memory.json +0 -49
- package/dist/schemas/decision-enforcement.json +0 -22
- package/dist/schemas/decision-memory.json +0 -54
- package/dist/schemas/dependency-health.json +0 -27
- package/dist/schemas/developer-dna.json +0 -219
- package/dist/schemas/ecosystem-pulse.json +0 -17
- package/dist/schemas/get-actionable-signals.json +0 -29
- package/dist/schemas/get-context.json +0 -17
- package/dist/schemas/get-relevant-content.json +0 -26
- package/dist/schemas/knowledge-gaps.json +0 -14
- package/dist/schemas/record-feedback.json +0 -24
- package/dist/schemas/upgrade-planner.json +0 -22
- package/dist/schemas/vulnerability-scan.json +0 -26
- package/dist/schemas/what-should-i-know.json +0 -19
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 6.0.0 — 2026-10-02
|
|
4
|
+
|
|
5
|
+
### New: `upgrade_impact`
|
|
6
|
+
|
|
7
|
+
What changes between the version you run and the one you want, for one npm
|
|
8
|
+
or crates.io dependency: the releases in between (publish dates, npm
|
|
9
|
+
deprecations, crates yanks), the changelog shipped inside the target
|
|
10
|
+
version's own registry archive with every entry classified breaking /
|
|
11
|
+
deprecation / security, the breaking entries that mention symbols your code
|
|
12
|
+
imports from the package (`touches_your_code`), the files that import it, and
|
|
13
|
+
the advisories the upgrade fixes or leaves. Only the package's registry and
|
|
14
|
+
OSV.dev are contacted; when the archive ships no changelog (fastembed, vite and
|
|
15
|
+
zod do not) the answer says so and gives the release-notes URL instead of
|
|
16
|
+
guessing.
|
|
17
|
+
|
|
18
|
+
Breaking changes in string literals are found too: the old syntax a breaking
|
|
19
|
+
entry names (axum 0.8's `/:single` -> `/{single}`) is matched in the
|
|
20
|
+
importing files' route and pattern strings, with file and line
|
|
21
|
+
(`matched_literals`).
|
|
22
|
+
|
|
23
|
+
Every entry carries the heading or parent bullet it sits under (`under`):
|
|
24
|
+
"`rt::{Arbiter}` re-exports." means nothing until you see it sits under
|
|
25
|
+
"Removed". Concise output keeps up to 20 plain changes per release under API
|
|
26
|
+
or neutral headings ("Changed", "Methods", "Types") and 3 under additive ones,
|
|
27
|
+
and says how many it left out.
|
|
28
|
+
|
|
29
|
+
How far the "breaking" flags go, measured: five corpora of real upgrades,
|
|
30
|
+
each rated blind by three independent raters. The last, 47 upgrades never
|
|
31
|
+
used to build the rules, rated by raters who saw each entry's heading
|
|
32
|
+
(Fleiss kappa 0.982), is the release measurement: 98.6% of entries flagged
|
|
33
|
+
breaking were breaking (95% CI 94.9-99.6%) and about 65% of breaking entries
|
|
34
|
+
were flagged. Earlier fresh corpora, before the last parser fixes, measured
|
|
35
|
+
73-87%, so the summary says "flagged", every answer states the measurement in
|
|
36
|
+
`_meta.classification`, and the agent is told to read every entry of a major
|
|
37
|
+
upgrade. Counts are `null` when the changelog has no entry for the releases
|
|
38
|
+
crossed, and labelled lower bounds when it covers only some. Changelog formats
|
|
39
|
+
read: keep-a-changelog and changesets headings, category headings at the
|
|
40
|
+
release's own level (date-fns), plain and bold label lines, releases as
|
|
41
|
+
bullets (indexmap), History.md label lists (express), day-first dates (knex),
|
|
42
|
+
RELEASE-NOTES.md (base64); layout markup (`<details>`) is skipped.
|
|
43
|
+
|
|
44
|
+
### New: `dependency_check` — a verdict before you add or bump a dependency
|
|
45
|
+
|
|
46
|
+
An agent calls it with up to 25 `{ ecosystem, package, to, from? }` items (npm
|
|
47
|
+
and crates.io) before it edits a manifest; `to: "latest"` checks the newest
|
|
48
|
+
stable release and reports which version that was (`to_requested`). Each item gets `proceed`, `wait`,
|
|
49
|
+
`review`, `avoid` or `unknown`, a one-line reason, and the signals behind it,
|
|
50
|
+
each with evidence: known OSV advisories on the target (and the ones the change
|
|
51
|
+
fixes), release age (under 3 days is `wait`, unless the release fixes an
|
|
52
|
+
advisory affecting the installed version), a drop in publish trust (trusted
|
|
53
|
+
publisher > provenance attestation > neither), npm install scripts the target
|
|
54
|
+
adds, runtime dependencies the target adds that were themselves first published
|
|
55
|
+
under 30 days earlier, yanked / deprecated / unpublished targets, and the
|
|
56
|
+
upgrade type. Against the axios 1.14.0 -> 1.14.1 compromise shape (token
|
|
57
|
+
publish replacing a trusted publisher, plus a dependency created the day
|
|
58
|
+
before) it answers `review` on both counts. A registry or OSV that cannot be
|
|
59
|
+
reached gives `unknown`, never `proceed`; a name missing from the public
|
|
60
|
+
registry says it may be private, misspelled or hallucinated.
|
|
61
|
+
|
|
62
|
+
Registry requests carry the package name only. The installed and target
|
|
63
|
+
versions are picked out of the full release list locally: npm's full packument
|
|
64
|
+
(cached on disk with its ETag and revalidated with `If-None-Match`) and the
|
|
65
|
+
crates.io versions API (spaced one request per second, with a descriptive
|
|
66
|
+
User-Agent) plus the sparse index for per-version dependencies.
|
|
67
|
+
|
|
68
|
+
### New: the `deps` prompt
|
|
69
|
+
|
|
70
|
+
The server now declares the MCP `prompts` capability. `deps` is a user-invoked
|
|
71
|
+
workflow: plan with `upgrade_planner`, vet each bump with `dependency_check`,
|
|
72
|
+
apply only `proceed` items in small batches with the project's tests after
|
|
73
|
+
each, report everything else with its evidence, and re-run
|
|
74
|
+
`vulnerability_scan` at the end.
|
|
75
|
+
|
|
76
|
+
### New: a Claude Code plugin, with a hook on dependency edits
|
|
77
|
+
|
|
78
|
+
Install with `claude plugin marketplace add 4DA-Systems/4DA --sparse
|
|
79
|
+
.claude-plugin mcp-4da-server` and `claude plugin install 4da@4da` (the
|
|
80
|
+
repository now carries the marketplace manifest the plugin needed to be
|
|
81
|
+
installable at all). After an Edit or MultiEdit that changes a dependency's
|
|
82
|
+
version in `package.json`, `Cargo.toml`, `pyproject.toml`, `requirements.txt`
|
|
83
|
+
or `go.mod`, the agent is told which packages moved and given the exact
|
|
84
|
+
`dependency_check` and `upgrade_impact` calls. A tool is called when the agent
|
|
85
|
+
thinks to; a hook fires on the edit itself. Plain Node, no network, silent for
|
|
86
|
+
every other edit, and it can never fail the edit. Verified end to end in a real
|
|
87
|
+
Claude Code session: the hook's context reaches the agent on the edit.
|
|
88
|
+
|
|
89
|
+
### Fixed: the vulnerability scan read lockfiles losslessly
|
|
90
|
+
|
|
91
|
+
Measured against osv-scanner on 12 projects, the matching was exact but the
|
|
92
|
+
lockfile reading lost findings (precision 0.74, recall 0.48 per advisory). Now
|
|
93
|
+
precision 1.00, recall 0.995:
|
|
94
|
+
- every installed copy is scanned, not one version per package name (nested
|
|
95
|
+
npm copies, two versions of a crate: 4DA's own `rsa 0.9.10` was missed);
|
|
96
|
+
- npm/pnpm/Pipfile/poetry dev flags make a transitive's dev scope known;
|
|
97
|
+
- Go: full pseudo-versions and `+incompatible`, `replace` directives, Go's build
|
|
98
|
+
list from `go.mod` (and `go.sum` before go 1.17);
|
|
99
|
+
- `requirements.txt` extras, dotted names, markers, comments and `--hash`
|
|
100
|
+
options; `poetry.lock` of any vintage, `uv.lock`, Poetry and PEP 621 manifests;
|
|
101
|
+
- Cargo virtual workspaces, and standalone mode scans every independently
|
|
102
|
+
locked project under the root, honouring `.gitignore`;
|
|
103
|
+
- `bun.lock` (Bun 1.2+), with dev scope from the workspaces;
|
|
104
|
+
- PEP 440 version order and PEP 503 names when choosing the fix version.
|
|
105
|
+
|
|
106
|
+
Before release the scan was re-run, from the packed tarball installed fresh,
|
|
107
|
+
on those 12 projects and on 11 more never used to build the readers (npm,
|
|
108
|
+
yarn v1, pnpm, bun, Cargo, Go, uv, Pipfile, Poetry): every project matches
|
|
109
|
+
osv-scanner or an independent oracle (OSV queried directly; Go's own
|
|
110
|
+
`go list -m all` build list, where the server reports modules osv-scanner
|
|
111
|
+
misses). The only misses are transitives of a `requirements.txt` without a
|
|
112
|
+
lockfile, documented below. Eight projects locked at current releases report
|
|
113
|
+
zero findings.
|
|
114
|
+
|
|
115
|
+
### Changed: answers only confirmed evidence can raise
|
|
116
|
+
|
|
117
|
+
- `what_should_i_know` is built from the task: the dependencies it names,
|
|
118
|
+
their installed versions, version-confirmed vulnerabilities, majors crossed.
|
|
119
|
+
Feed headlines no longer drive the delegation verdict (a security keyword
|
|
120
|
+
in an arXiv paper or in OpenAI company news forced `human_only` for any task).
|
|
121
|
+
- `get_actionable_signals` no longer classifies items by keyword; it shows the
|
|
122
|
+
desktop app's classifications only when its relevance judge accepted the item,
|
|
123
|
+
and a headline is never above medium unless it comes from an advisory database.
|
|
124
|
+
- `get_relevant_content` and `knowledge_gaps` leave out judge-rejected items.
|
|
125
|
+
- `upgrade_planner` targets the smallest version that fixes the advisories, not
|
|
126
|
+
the newest major; unmaintained-package notices are not counted as CVEs. It
|
|
127
|
+
and `dependency_health` run the OSV scan themselves when none has run (they
|
|
128
|
+
answered "run vulnerability_scan first", leaving the first answer of a
|
|
129
|
+
session CVE-blind),
|
|
130
|
+
and `package` finds a vulnerable transitive instead of calling it "not a
|
|
131
|
+
dependency".
|
|
132
|
+
- `vulnerability_scan` takes `package`: one dependency's findings across every
|
|
133
|
+
installed copy, with a `package_note` saying what the lockfiles hold for it.
|
|
134
|
+
An agent asked about one transitive otherwise read the whole report.
|
|
135
|
+
- A scan that finishes late no longer replaces a newer one: the startup scan
|
|
136
|
+
(devDependencies left out) could overwrite an agent's `include_dev` scan, and
|
|
137
|
+
the planner then sent the devDependency node-fetch 2.6.0 to the ESM-only 3.3.2
|
|
138
|
+
with no advisories (2 runs in 6). A plan or briefing that needs
|
|
139
|
+
devDependencies covered scans at that scope instead of reading a narrower scan.
|
|
140
|
+
- Desktop mode finds the app's database on Linux (`$XDG_DATA_HOME/4da/data`, as
|
|
141
|
+
the app writes it) and honours the app's `FOURDA_DATA_DIR`.
|
|
142
|
+
|
|
143
|
+
### Changed: the protocol surface
|
|
144
|
+
|
|
145
|
+
- Every tool now lists all its parameters in `tools/list` (most were hidden).
|
|
146
|
+
- Server `instructions` for hosts with tool search; argument errors come back as
|
|
147
|
+
`isError` with the fix; `structuredContent` beside the text; compact JSON;
|
|
148
|
+
invisible and control characters stripped from third-party text.
|
|
149
|
+
- `tools/list` no longer waits for the project scan (6.6 s measured).
|
|
150
|
+
- `agent_memory` and `decision_memory` match their published schemas (recall
|
|
151
|
+
takes `query`, store takes `subject`; the old schema could not be followed).
|
|
152
|
+
|
|
153
|
+
### Breaking
|
|
154
|
+
|
|
155
|
+
- Node.js 22 or later. better-sqlite3 publishes no Node 20 binary from 12.10,
|
|
156
|
+
so a Node 20 install compiled from source and failed on any machine without
|
|
157
|
+
Python and a C++ toolchain (every slim container); Node 20 reached end of
|
|
158
|
+
life in April 2026. Verified installs: Node 20 (with a toolchain), 22 and 24
|
|
159
|
+
on Windows; Node 22 on Debian and Alpine Linux; Node 24 on Debian.
|
|
160
|
+
- npm 12 blocks dependency install scripts unless allowed, so better-sqlite3
|
|
161
|
+
is left unbuilt by both `npx` and `npm install`. `--doctor` now opens a
|
|
162
|
+
database instead of trusting the import; it had reported the bindings as
|
|
163
|
+
loaded while every tool failed with "Could not locate the bindings file".
|
|
164
|
+
That error now carries the fix: `npm config set
|
|
165
|
+
allow-scripts=better-sqlite3 --location=user` and `npx clear-npx-cache`, or
|
|
166
|
+
`npm install-scripts approve better-sqlite3` and `npm rebuild
|
|
167
|
+
better-sqlite3`. Each was verified on npm 12.2.0. npm 10 and 11, which every
|
|
168
|
+
current Node release ships, are not affected.
|
|
169
|
+
- `upgrade_impact`'s summary says "N entries flagged breaking", not "N
|
|
170
|
+
breaking changes": the flags are a pre-sort, and every entry now carries its
|
|
171
|
+
heading (`under`).
|
|
172
|
+
- `vulnerability_scan` answers in a concise form by default: `vulnerable_packages`
|
|
173
|
+
has one row per vulnerable package version (worst severity, the version that
|
|
174
|
+
fixes all its advisories, advisory count and first ids), the 40 most severe,
|
|
175
|
+
with 25 recommendations and a count of anything left out. `by_severity` still
|
|
176
|
+
counts every advisory. Pass `response_format: "detailed"` for the previous
|
|
177
|
+
full report, one row per advisory. One row per advisory came to about 25k
|
|
178
|
+
tokens on large projects, the size at which Claude Code cuts a tool answer
|
|
179
|
+
off.
|
|
180
|
+
- `get_actionable_signals` returns fewer items: unclassified and judge-rejected
|
|
181
|
+
ones are gone by design.
|
|
182
|
+
- Tool schemas are no longer separate JSON files (`dist/schemas/`); the
|
|
183
|
+
`4da://schema/<tool>` resources serve them from the tool definitions.
|
|
184
|
+
- A standalone database is created in the user data folder, not in
|
|
185
|
+
`<cwd>/data/4da.db`. An existing one there is still found and used.
|
|
186
|
+
- Hacker News is contacted only when `ecosystem_pulse` is called, never at startup.
|
|
187
|
+
|
|
188
|
+
### Changed: `upgrade_planner` returns the 4DA app's plan when there is one
|
|
189
|
+
|
|
190
|
+
The tool used to compute its own plan from the lockfiles in the current
|
|
191
|
+
directory, even on a machine where the 4DA app had already computed one. An
|
|
192
|
+
agent could be told a different target than the app showed for the same
|
|
193
|
+
install. When the app's database holds its persisted Upgrade Plan (schema 4),
|
|
194
|
+
the tool now returns that plan's work order with `provenance.mode: "app_plan"`:
|
|
195
|
+
one step per package, keyed by the app's item id, with the ecosystem, each
|
|
196
|
+
installed version and its minimum clean target, the upgrade type
|
|
197
|
+
(patch/minor/major), the projects holding it (direct or transitive, dev or
|
|
198
|
+
not) and the mechanism. `manifest_bump` means edit the manifest;
|
|
199
|
+
`lockfile_or_parent_update` means the package is only transitive, so update its
|
|
200
|
+
parent or refresh the lockfile rather than adding it as a direct dependency.
|
|
201
|
+
Past the plan's `expires_at` the result says `stale: true` and is still the
|
|
202
|
+
app's plan. Without a usable plan (no app database, nothing computed yet, or a
|
|
203
|
+
snapshot from another app version) the tool runs the standalone heuristic as
|
|
204
|
+
before and says why in `appPlanUnavailable`. The server reads the plan; it
|
|
205
|
+
does not reimplement the app's matching. `package` narrows either plan to one
|
|
206
|
+
package.
|
|
207
|
+
|
|
208
|
+
## 5.1.0 — 2026-09-11
|
|
209
|
+
|
|
210
|
+
### Fixed: scoped packages in pnpm and yarn lockfiles were never scanned
|
|
211
|
+
|
|
212
|
+
`vulnerability_scan` asked OSV about `'@humanfs/node`, with a leading quote,
|
|
213
|
+
instead of `@humanfs/node`. So GHSA-p498-v437-472g never appeared, although it
|
|
214
|
+
was open as Dependabot alert 340 on this repository and the app showed it. The
|
|
215
|
+
pnpm reader matched package keys with a pattern whose `\s` crossed the blank
|
|
216
|
+
line pnpm writes between entries, and so kept the next key's quote. Every
|
|
217
|
+
scoped package outside the importer blocks was affected: 525 names across five
|
|
218
|
+
lockfiles in this repository (measured 2026-09-11). The test fixture had no
|
|
219
|
+
blank lines, so it passed. The reader now matches keys by column on whole
|
|
220
|
+
lines, reads pnpm lockfile v5, v6 and v9, and drops keys that pin no registry
|
|
221
|
+
version (git, tarball, file) instead of querying them as names. The yarn
|
|
222
|
+
reader could not match a header that starts with `@`, so it dropped every
|
|
223
|
+
scoped package, and it never read yarn berry's `version: x` lines. Both are
|
|
224
|
+
fixed. Expect more findings on a pnpm or yarn project after upgrading; they
|
|
225
|
+
were always there.
|
|
226
|
+
|
|
227
|
+
### Fixed: a patched lockfile no longer hides a vulnerable node_modules
|
|
228
|
+
|
|
229
|
+
`mcp-4da-server/pnpm-lock.yaml` pinned hono 4.13.5 (the fix for
|
|
230
|
+
CVE-2026-84363/-84364/-84365) while `mcp-4da-server/node_modules` held 4.13.1
|
|
231
|
+
for 25 days, because activation ran `pnpm install` only at the repo root.
|
|
232
|
+
Every 4DA surface reads the lockfile, so every surface reported hono fixed
|
|
233
|
+
while the vulnerable copy was the one that ran (measured 2026-09-10). For npm
|
|
234
|
+
direct dependencies resolved from a lockfile, the server now reads
|
|
235
|
+
`node_modules/<name>/package.json` (scoped names included; hoisted workspaces
|
|
236
|
+
by walking up to the repository root, at most six levels). A directory with
|
|
237
|
+
no `node_modules` of its own is skipped, and a manifest-only resolution is
|
|
238
|
+
never compared, because a specifier floor is not a pin. When the installed
|
|
239
|
+
version differs, OSV is asked about the installed version too, so the answer
|
|
240
|
+
is OSV's, not a guess.
|
|
241
|
+
|
|
242
|
+
`vulnerability_scan` gains `install_drift: [{ package, dir, lockfile_version,
|
|
243
|
+
installed_version, vulnerable_installed, lockfile_version_vulnerable, fix,
|
|
244
|
+
note }]`, where `fix` is `pnpm install`, `npm ci` or `yarn install` according
|
|
245
|
+
to the lockfile that pinned the version. Each affected vulnerability carries
|
|
246
|
+
`installed_version`, `lockfile_version` and an `install_note` ("the lockfile
|
|
247
|
+
is patched but node_modules still has 4.13.1 — run `pnpm install`"), and the
|
|
248
|
+
recommendation is the reinstall, not an upgrade the lockfile is already past.
|
|
249
|
+
`what_should_i_know` names a vulnerable installed copy with its reinstall
|
|
250
|
+
command whatever the task, so the verdict is at least `review_needed` and
|
|
251
|
+
never clean. That advisory is graded the way the app grades its install-drift
|
|
252
|
+
row: high when the reinstall clears an advisory the running copy has (the
|
|
253
|
+
hono case, though its three advisories are medium on their own), medium when
|
|
254
|
+
the lockfile's pinned version is exposed too. `dependency_health` and `upgrade_planner` show `installedVersion`
|
|
255
|
+
beside `currentVersion`, and `upgrade_planner` turns a drift-only row into a
|
|
256
|
+
`reinstall` step. Expect `install_drift: []` on a healthy checkout.
|
|
257
|
+
|
|
258
|
+
### Fixed: a long-running server answered for the dependency set it saw at startup
|
|
259
|
+
|
|
260
|
+
Three server processes were live on the founder machine. Two had started
|
|
261
|
+
before the pull that brought hono 4.13.5, and `vulnerability_scan` from one
|
|
262
|
+
of them reported hono 4.13.3 (the lockfile at its start) with
|
|
263
|
+
`_meta.cached: false`: versions were resolved once at init and never again,
|
|
264
|
+
and `cached` only ever described the OSV lookup. Each resolution group now
|
|
265
|
+
records the files it read as stat signatures (every lockfile candidate,
|
|
266
|
+
present or absent; the manifest when the resolver fell back to it; for npm,
|
|
267
|
+
the node_modules install state). `vulnerability_scan`, `what_should_i_know`,
|
|
268
|
+
`dependency_health`, `upgrade_planner` and the briefing's scan wait re-run the
|
|
269
|
+
same resolution when one changes, and drop the stored scan and the warmup so
|
|
270
|
+
no answer describes a dependency set that no longer exists. Stat calls only:
|
|
271
|
+
no timers, no watchers. The cargo host-platform memo is keyed on
|
|
272
|
+
`Cargo.lock`/`Cargo.toml` too, so a re-resolution cannot mark newly added
|
|
273
|
+
crates as not built on this host.
|
|
274
|
+
|
|
275
|
+
### Added: resolution provenance
|
|
276
|
+
|
|
277
|
+
`vulnerability_scan`'s `_meta` gains `resolution: { resolved_at, lockfiles:
|
|
278
|
+
[{ path, kind, mtime }], re_resolved_this_call, note }` and `osv_cached` (the
|
|
279
|
+
same value as `cached`, which stays for compatibility). The tool description
|
|
280
|
+
now says that `cached` refers to the OSV advisory lookup, not to dependency
|
|
281
|
+
resolution. `what_should_i_know` gains a `scan` block (`status`,
|
|
282
|
+
`scanned_at`, `resolved_at`, `re_resolved_this_call`); `scan_status` stays.
|
|
283
|
+
|
|
284
|
+
### Changed: one severity rule with the desktop app (AD-046)
|
|
285
|
+
|
|
286
|
+
`vulnerability_scan` graded `sandbox@3.1.2`, a transitive of paddle-webhook
|
|
287
|
+
whose dev/runtime scope is unknown, critical (`by_severity.critical: 1`; the
|
|
288
|
+
briefing said "CRITICAL: Sandbox Breakout"), while the app graded the same
|
|
289
|
+
advisory High. Every surface now presents one grade, the rule the app uses
|
|
290
|
+
(`osv::identity::scope_adjusted_urgency`): a transitive-only dependency caps
|
|
291
|
+
critical at high, then a dev-only dependency drops one level (critical to
|
|
292
|
+
high, high to medium, medium to low; low and unknown stay). Unknown dev scope
|
|
293
|
+
gets no discount. Applied in `vulnerability_scan`, `what_should_i_know` and
|
|
294
|
+
`get_actionable_signals`; `severity_filter` and sorting use the presented
|
|
295
|
+
grade. Nothing is hidden: every entry keeps the advisory's own tier as
|
|
296
|
+
`advisory_severity` (with a `severity_note` when the two differ),
|
|
297
|
+
`by_severity` counts the presented grade, and the new `advisory_by_severity`
|
|
298
|
+
counts the raw tiers.
|
|
299
|
+
|
|
300
|
+
In full-database mode a transitive's dev scope comes from the app's
|
|
301
|
+
`dependency_instances` table. Only a real determination counts (`is_dev = 1`,
|
|
302
|
+
or a `scope` of runtime, dev or build); the app's placeholder rows
|
|
303
|
+
(`is_dev = 0, scope = 'unknown'`) stay unknown. Without `include_dev`, only
|
|
304
|
+
direct devDependencies are left out of the scan: a transitive of known dev
|
|
305
|
+
scope is graded down, not dropped, and one of unknown scope is no longer
|
|
306
|
+
hidden because a direct devDependency shares its name.
|
|
307
|
+
|
|
308
|
+
### Added: the database-recovery voice in data_freshness
|
|
309
|
+
|
|
310
|
+
When the headless refresh engine restores `4da.db` from a backup, or
|
|
311
|
+
quarantines it and starts a fresh empty one, it leaves `data/.db-recovered`
|
|
312
|
+
beside it. A fresh database looks fresh by every other freshness field.
|
|
313
|
+
`data_freshness` now surfaces the marker the way it surfaces `.engine-blocked`:
|
|
314
|
+
`db_recovered_at`, `db_recovery_kind`, `db_recovery_detail`, and a note ("The
|
|
315
|
+
database was restored from a backup / replaced with a fresh empty database by
|
|
316
|
+
the background refresh at … — results may be incomplete or empty; the
|
|
317
|
+
preserved file is …"). Read-only: the desktop app shows the marker once and
|
|
318
|
+
deletes it.
|
|
319
|
+
|
|
320
|
+
### Changed: ranked reads break ties by id
|
|
321
|
+
|
|
322
|
+
`get_relevant_content` orders by `COALESCE(rank_score, relevance_score) DESC,
|
|
323
|
+
id DESC`, mirroring the app's `RANKED_ORDER_EXPR`. 100 of 651 surfaced items
|
|
324
|
+
sat at exactly 0.5000 (a hard score cap), and their order was whatever SQLite
|
|
325
|
+
emitted.
|
|
326
|
+
|
|
327
|
+
### Changed: dependency_health says when it has no CVE data
|
|
328
|
+
|
|
329
|
+
`dependency_health` no longer says "all healthy" without a vulnerability scan
|
|
330
|
+
behind it, and says so when CVE data is not loaded (no scan yet, or the
|
|
331
|
+
dependencies changed since the last one).
|
|
332
|
+
|
|
333
|
+
### Fixed: the briefing never answers "safe" without a vulnerability scan
|
|
334
|
+
|
|
335
|
+
`what_should_i_know` awaited nothing. In full-database mode the live layer was
|
|
336
|
+
initialised without a vulnerability scan, so the first call after start read
|
|
337
|
+
an empty cache and reported `safe_to_delegate` for a task that named a package
|
|
338
|
+
with an open advisory (verified live 2026-09-07: 0 advisories at t+0, 11 at
|
|
339
|
+
t+7 min). The scan now warms at server start, the briefing awaits it (bounded,
|
|
340
|
+
8 s), and the result carries `scan_status` (`ready` | `unavailable` |
|
|
341
|
+
`disabled`). Without a ready scan the delegation level is the new `"unknown"`
|
|
342
|
+
— treat the task as unreviewed, never as safe; `safe_to_delegate` is only
|
|
343
|
+
emitted over a ready scan. Existing `human_only` evidence still wins.
|
|
344
|
+
|
|
345
|
+
Security signals now also come through a 30-day feed pass (`since_hours` max
|
|
346
|
+
raised from 168 to 720; windows past 7 days keep the current-pipeline-version
|
|
347
|
+
guard), so a three-day-old advisory is no longer cut by the 72-hour window. A
|
|
348
|
+
relevant security or breaking-change advisory yields at least `review_needed`.
|
|
349
|
+
|
|
350
|
+
### Fixed: one signal per vulnerability
|
|
351
|
+
|
|
352
|
+
`get_actionable_signals` injected one live signal per OSV record, so a
|
|
353
|
+
GHSA/RUSTSEC pair for one bug read as two problems. Alias-connected records
|
|
354
|
+
are clustered (union-find, scoped to package + version) and emitted once,
|
|
355
|
+
every id in `triggers`. Platform-inactive advisories and maintenance notices
|
|
356
|
+
drop to `low` with an explanatory action, and the briefing does not read them.
|
|
357
|
+
|
|
358
|
+
A `signal_type` filter is now pushed into the database read: the general read
|
|
359
|
+
is capped at the top 200 ranked items across every type, and on the live
|
|
360
|
+
corpus that cap starved a security-only pass (both in-window stored security
|
|
361
|
+
alerts ranked 299th and 582nd). The pipeline's stored priority vocabulary
|
|
362
|
+
(`critical` / `alert` / `advisory` / `watch`) is mapped onto the tool's tiers
|
|
363
|
+
instead of cast through unchanged — 92 of 93 stamped rows carried a priority
|
|
364
|
+
no filter, sort, or briefing rule recognised.
|
|
365
|
+
|
|
366
|
+
### Fixed: knowledge_gaps coverage and grading
|
|
367
|
+
|
|
368
|
+
- Every direct dependency is scanned (a `LIMIT 100` left 43 of 143 live
|
|
369
|
+
dependencies unexamined); candidate items are loaded once.
|
|
370
|
+
- Registry rows (`crates_io`, `npm_registry`, `pypi`, `go_modules`) are version
|
|
371
|
+
updates and grade `medium` regardless of title words — when the row is newer
|
|
372
|
+
than the installed version (the row for the version you run is not a gap).
|
|
373
|
+
- An advisory names a dependency when the dependency is its subject package
|
|
374
|
+
(`[ID] package: …`), not when the title merely contains the word: `url` was
|
|
375
|
+
graded critical on a SurrealDB advisory ("via URL path"), `hmac` on a
|
|
376
|
+
Phalcon one.
|
|
377
|
+
- An advisory the installed version is positively inside survives the 90-day
|
|
378
|
+
publish-date cut; unknown exposure does not exempt.
|
|
379
|
+
- `osv_advisories` is consulted for the dependency's own ecosystem (the npm
|
|
380
|
+
and crates.io `jsonwebtoken` were being conflated).
|
|
381
|
+
|
|
382
|
+
### Fixed: dependency_health counts vulnerable packages the way vulnerability_scan does
|
|
383
|
+
|
|
384
|
+
`vulnerableCount` is the actionable set (built on this host, not a maintenance
|
|
385
|
+
notice); `advisoryCount` reports every row so nothing is hidden. The health
|
|
386
|
+
penalty and severity breakdown follow the same set.
|
|
387
|
+
|
|
388
|
+
## 5.0.4 (2026-08-24)
|
|
389
|
+
|
|
390
|
+
### Fixed: vulnerability_scan could recommend a downgrade
|
|
391
|
+
|
|
392
|
+
`fixed_version` selection took the first OSV range's fix regardless of which
|
|
393
|
+
range contains the installed version — live consequence: "Upgrade undici to
|
|
394
|
+
6.28.0" while on 7.28.0. Selection is now branch-aware (the fix comes from the
|
|
395
|
+
range containing the installed version), with a hard guard that a
|
|
396
|
+
recommendation is never below the installed version — if no fix at or above it
|
|
397
|
+
exists, the honest "no fix version published" line is emitted instead.
|
|
398
|
+
|
|
399
|
+
### Changed: ranked reads follow the app's evidence/rank split
|
|
400
|
+
|
|
401
|
+
`get_relevant_content` orders by `COALESCE(rank_score, relevance_score)`
|
|
402
|
+
(schema 110, guarded for older databases); membership thresholds stay on the
|
|
403
|
+
evidence score.
|
|
404
|
+
|
|
405
|
+
## 5.0.3 (2026-08-23)
|
|
406
|
+
|
|
407
|
+
### Fixed: standalone mode broke on its second session (critical)
|
|
408
|
+
|
|
409
|
+
The minimal standalone schema created `dependencies` without the `is_direct`
|
|
410
|
+
column, while the live-intelligence init queried it. Session 1 of a standalone
|
|
411
|
+
install worked (fresh scan); session 2+ threw on init, the error was swallowed,
|
|
412
|
+
and `vulnerability_scan` / `dependency_health` / `upgrade_planner` silently
|
|
413
|
+
reported "no project detected" — blaming the user's setup. The column is now in
|
|
414
|
+
the minimal schema and an `ensureColumn` upgrade heals existing standalone DBs
|
|
415
|
+
on open.
|
|
416
|
+
|
|
417
|
+
### Fixed: grounded tool output
|
|
418
|
+
|
|
419
|
+
- `knowledge_gaps`: word-boundary matching with relevance/recency guards and
|
|
420
|
+
honest severity (previously substring matches like "invite" → vite, and
|
|
421
|
+
everything reported "critical").
|
|
422
|
+
- `ecosystem_pulse`: returns headlines again (dependency prefetch + on-demand
|
|
423
|
+
fetch + 14-day recency window; previously reproducibly empty).
|
|
424
|
+
- `what_should_i_know`: the decision-windows section was dead (ordered by a
|
|
425
|
+
column that does not exist on that table — `created_at` vs `opened_at`).
|
|
426
|
+
- Version logic: no more prerelease "upgrades" (rsa 0.10.0-rc downgrade) or
|
|
427
|
+
phantom stable versions (React "19.0.8") — stable-semver comparison
|
|
428
|
+
throughout.
|
|
429
|
+
- `dependency_health`: healthScore is proportional instead of collapsing to
|
|
430
|
+
0/100; feed output deduplicated (title similarity).
|
|
431
|
+
|
|
432
|
+
### Changed: tools/list serves real schemas for required-param tools (AD-032)
|
|
433
|
+
|
|
434
|
+
Tools whose schema declares required parameters (`record_feedback`,
|
|
435
|
+
`decision_memory`, `agent_memory`, `check_decision_alignment`,
|
|
436
|
+
`what_should_i_know`) now serve their real `inputSchema` in `tools/list` —
|
|
437
|
+
the slim `{"type":"object"}` made them uncallable for clients that never read
|
|
438
|
+
MCP Resources. All-optional tools stay slim; full schemas remain available at
|
|
439
|
+
`4da://schema/{tool}`.
|
|
440
|
+
|
|
441
|
+
## 5.0.2 (2026-08-17)
|
|
442
|
+
|
|
443
|
+
### Docs: republish so npm serves the corrected README
|
|
444
|
+
|
|
445
|
+
No code changes. 5.0.1 was published to npm on 2026-08-16 minutes before the
|
|
446
|
+
AD-030 copy retirement (#469) landed the corrected README, so the npm package
|
|
447
|
+
page still described "Compound intelligence (learns over time)" and content that "compounds over time" — claims the product retired. <!-- retired-ok: quotes the retired claims verbatim to document exactly what this republish removed from npm -->
|
|
448
|
+
This release exists to put the current README (and the corrected app-vs-MCP
|
|
449
|
+
comparison) on npm.
|
|
450
|
+
|
|
451
|
+
## 5.0.1 (2026-08-16)
|
|
452
|
+
|
|
453
|
+
### Security: HTTP transport accepted forged authentication tokens
|
|
454
|
+
|
|
455
|
+
**Affects `--http` only. The default stdio transport was never exposed.**
|
|
456
|
+
|
|
457
|
+
`extractAuthClaims` decoded the JWT payload and validated the claims inside it
|
|
458
|
+
but never read the signature segment — no HMAC was ever computed, despite the
|
|
459
|
+
function's own docstring claiming "HMAC-SHA256 verification against the shared
|
|
460
|
+
relay secret". Any request could present
|
|
461
|
+
`Authorization: Bearer x.<base64url({"team_id":"x","client_id":"y","role":"admin","exp":9999999999})>.x`
|
|
462
|
+
and be accepted as a team admin.
|
|
463
|
+
|
|
464
|
+
Three defects compounded it:
|
|
465
|
+
|
|
466
|
+
- The transport's header claimed "Binds to 127.0.0.1 only", but `--host`
|
|
467
|
+
accepted any address, so `--http --host 0.0.0.0` served all 14 tools to the
|
|
468
|
+
network.
|
|
469
|
+
- The DNS rebinding guard was written as `if (origin) { ...check... }`, so a
|
|
470
|
+
request with **no** `Origin` header — every non-browser client, and any
|
|
471
|
+
attacker — skipped it entirely.
|
|
472
|
+
- `hasPermission()` existed but was never called, so even legitimate tokens got
|
|
473
|
+
no role enforcement: a `viewer` could invoke every write tool.
|
|
474
|
+
|
|
475
|
+
Fixed:
|
|
476
|
+
|
|
477
|
+
- **Real signature verification.** HMAC-SHA256 over
|
|
478
|
+
`base64url(header).base64url(payload)`, constant-time compared
|
|
479
|
+
(`crypto.timingSafeEqual`) against the shared secret, **before** any claim is
|
|
480
|
+
read. The algorithm is pinned to `HS256`, so `alg: none`, other HMAC widths,
|
|
481
|
+
and asymmetric-algorithm confusion are all refused. `exp` is now mandatory
|
|
482
|
+
(a signed token with no expiry is a permanent credential) and `nbf` is
|
|
483
|
+
honoured, both with the issuer's 60s leeway. No new dependency — Node's
|
|
484
|
+
built-in `node:crypto`.
|
|
485
|
+
- **Fail closed.** With no secret configured (`MCP_AUTH_SECRET`, falling back
|
|
486
|
+
to `JWT_SECRET` for parity with a co-deployed relay), *every* token is
|
|
487
|
+
rejected. A server that cannot verify a signature must not trust claims.
|
|
488
|
+
- **Host-header DNS rebinding guard on every request**, using the SDK's
|
|
489
|
+
`validateHostHeader`/`validateOriginHeader`. `Host` is mandatory, so the
|
|
490
|
+
check can no longer be skipped by omitting a header; a foreign `Origin` is
|
|
491
|
+
still refused when present.
|
|
492
|
+
- **Safe `--host`.** 127.0.0.1 remains the default. A non-loopback bind is
|
|
493
|
+
**refused at startup** unless a secret is configured, prints a warning
|
|
494
|
+
banner, and forces authentication on for every request regardless of
|
|
495
|
+
`MCP_AUTH_REQUIRED`.
|
|
496
|
+
- **Role enforcement wired up.** Every tool call is checked against the
|
|
497
|
+
verified role via the registry's existing `readOnlyHint` annotation:
|
|
498
|
+
`viewer` = read-only, `member`/`admin` = read + write. Unknown tools fail
|
|
499
|
+
closed as writes.
|
|
500
|
+
- Removed `isNetworkTierAllowed()` — dead code with no tier data anywhere in
|
|
501
|
+
this package.
|
|
502
|
+
|
|
503
|
+
**Behaviour change:** an existing `--http --host 0.0.0.0` deployment will now
|
|
504
|
+
refuse to start until `MCP_AUTH_SECRET` is set, and only accepts localhost-class
|
|
505
|
+
`Host` headers unless `MCP_ALLOWED_HOSTS` names the address clients use. This is
|
|
506
|
+
deliberate: that deployment was previously reachable by anyone with forgeable
|
|
507
|
+
admin credentials.
|
|
508
|
+
|
|
509
|
+
## 5.0.0 (2026-08-11)
|
|
510
|
+
|
|
511
|
+
### Breaking: Node.js 20+ required
|
|
512
|
+
|
|
513
|
+
The server now requires Node.js >= 20 (previously >= 18; Node 18 has been EOL
|
|
514
|
+
since April 2025). No tool behavior changes.
|
|
515
|
+
|
|
516
|
+
### Changed: migrated to MCP TypeScript SDK v2 + 2026-07-28 protocol support
|
|
517
|
+
|
|
518
|
+
Replaced the discontinued `@modelcontextprotocol/sdk` v1 with the v2 packages
|
|
519
|
+
(`@modelcontextprotocol/server` + `@modelcontextprotocol/node`) and moved both
|
|
520
|
+
transports onto the v2 serving entries:
|
|
521
|
+
|
|
522
|
+
- **stdio** now goes through `serveStdio`, which negotiates the protocol era
|
|
523
|
+
per connection: 2025-era hosts (Claude Code, Claude Desktop, Cursor — the
|
|
524
|
+
classic `initialize` handshake) are served exactly as before, and hosts
|
|
525
|
+
speaking the new stateless 2026-07-28 revision (`server/discover`) are now
|
|
526
|
+
supported on the same endpoint.
|
|
527
|
+
- **--http** now goes through `createMcpHandler` + `toNodeHandler`: stateless
|
|
528
|
+
serving for both eras from one factory — the previous per-request transport
|
|
529
|
+
wiring is gone. Health endpoint, localhost binding, Origin-header DNS
|
|
530
|
+
rebinding protection, and the optional JWT auth gate are unchanged.
|
|
531
|
+
|
|
532
|
+
Existing clients need no changes — protocol version negotiation is untouched
|
|
533
|
+
for 2025-era hosts and verified against a v1-SDK client.
|
|
534
|
+
|
|
535
|
+
### Fixed: startup log reported a stale version
|
|
536
|
+
|
|
537
|
+
The stdio startup line hardcoded "v4.6.3" regardless of the installed version;
|
|
538
|
+
it now derives from package.json like `--version` and `serverInfo`.
|
|
539
|
+
|
|
540
|
+
## 4.6.2 (2026-06-17)
|
|
541
|
+
|
|
542
|
+
### Fixed: vulnerability_scan returned empty severity, fix versions, and summaries
|
|
543
|
+
|
|
544
|
+
The scanner enumerated advisories via OSV's `/v1/querybatch` endpoint, which returns
|
|
545
|
+
only `{ id, modified }` per vulnerability — but it then mapped that index-only object
|
|
546
|
+
as if it were the full record. Every rich field collapsed to a default: `summary`
|
|
547
|
+
became the bare advisory ID, `fixed_version` was always `null` (so every
|
|
548
|
+
recommendation read "no fix version published"), `references` was always empty,
|
|
549
|
+
`published` actually carried the *modified* timestamp, and severity was hardcoded
|
|
550
|
+
(`medium` for any GHSA, `unknown` for anything else) rather than derived.
|
|
551
|
+
|
|
552
|
+
The scanner now hydrates each matched advisory via `/v1/vulns/{id}` (cache-first,
|
|
553
|
+
24h TTL, bounded concurrency over the vulnerable subset only) and derives severity
|
|
554
|
+
honestly: a CVSS base score — computed from the vector string when OSV provides one
|
|
555
|
+
(new `cvss.ts`, CVSS v3.0/3.1) — wins, then the GitHub-advisory severity label, then
|
|
556
|
+
`unknown`. No more fabricated default buckets. Real fix versions, CVE aliases,
|
|
557
|
+
summaries, and reference links now flow through.
|
|
558
|
+
|
|
559
|
+
## 4.6.1 (2026-06-11)
|
|
560
|
+
|
|
561
|
+
### Improved: prescriptive tool descriptions
|
|
562
|
+
|
|
563
|
+
All 14 tool descriptions now state WHEN to call the tool, not just what it does
|
|
564
|
+
(e.g. "Call when the user asks about security, vulnerabilities, or CVEs"). Both the
|
|
565
|
+
slim tool list and the full schemas carry explicit triggers, so calling models select
|
|
566
|
+
the right tool more reliably. A regression test enforces this going forward.
|
|
567
|
+
|
|
568
|
+
### Changed: license
|
|
569
|
+
|
|
570
|
+
Relicensed to Apache-2.0 (from MIT). The 4DA desktop app remains under
|
|
571
|
+
FSL-1.1-Apache-2.0; this MCP connector is intentionally permissive to maximize adoption.
|
|
572
|
+
|
|
573
|
+
## 4.6.0 (2026-04-24)
|
|
574
|
+
|
|
575
|
+
### Breaking: Tool consolidation — 39 → 14 tools
|
|
576
|
+
|
|
577
|
+
Removed 25 tools that returned empty, broken, or low-value data through MCP.
|
|
578
|
+
Every remaining tool reliably returns useful, actionable information.
|
|
579
|
+
|
|
580
|
+
**Kept (14):**
|
|
581
|
+
- `vulnerability_scan` — live CVE scanning (standalone)
|
|
582
|
+
- `dependency_health` — health score + version freshness (standalone)
|
|
583
|
+
- `upgrade_planner` — ranked upgrade recommendations (standalone)
|
|
584
|
+
- `what_should_i_know` — pre-task intelligence briefing (standalone)
|
|
585
|
+
- `ecosystem_pulse` — filtered ecosystem news (standalone)
|
|
586
|
+
- `get_context` — tech stack + interests (standalone)
|
|
587
|
+
- `get_relevant_content` — scored content feed (full mode)
|
|
588
|
+
- `get_actionable_signals` — classified alerts (full mode)
|
|
589
|
+
- `knowledge_gaps` — dependency blind spots (full mode)
|
|
590
|
+
<!-- retired-ok: historical release notes — describes that release's tool list verbatim -->
|
|
591
|
+
- `record_feedback` — save/dismiss to teach the system (full mode)
|
|
592
|
+
- `decision_memory` — persistent architectural decisions (standalone)
|
|
593
|
+
- `check_decision_alignment` — verify tech choices (standalone)
|
|
594
|
+
- `agent_memory` — cross-session persistent memory (standalone)
|
|
595
|
+
- `developer_dna` — tech identity profile (full mode)
|
|
596
|
+
|
|
597
|
+
**Removed:** explain_relevance, score_autopsy, trend_analysis, daily_briefing,
|
|
598
|
+
context_analysis, topic_connections, signal_chains, semantic_shifts,
|
|
599
|
+
attention_report, source_health, config_validator, llm_status,
|
|
600
|
+
export_context_packet, reverse_mentions, project_health, tech_radar,
|
|
601
|
+
agent_session_brief, delegation_score, autophagy_status, decision_windows,
|
|
602
|
+
compound_advantage, record_agent_feedback, get_agent_feedback_stats,
|
|
603
|
+
trust_summary, preemption_feed
|
|
604
|
+
|
|
605
|
+
**Fixed:**
|
|
606
|
+
- `get_relevant_content` now uses Rust-computed PASIFA scores when the desktop
|
|
607
|
+
app database is present, instead of the simplified TypeScript keyword scorer.
|
|
608
|
+
Results are dramatically more accurate.
|
|
609
|
+
|
|
610
|
+
## 1.0.0 (2026-02-27)
|
|
611
|
+
|
|
612
|
+
Initial public release.
|
|
613
|
+
|
|
614
|
+
### Tools (27)
|
|
615
|
+
|
|
616
|
+
**Content & Scoring**
|
|
617
|
+
- `get_relevant_content` — Query filtered content by relevance, source, time
|
|
618
|
+
- `explain_relevance` — Understand why an item scored the way it did
|
|
619
|
+
- `record_feedback` — Teach 4DA what you like/dislike (click, save, dismiss)
|
|
620
|
+
- `score_autopsy` — Deep forensic analysis of relevance scores
|
|
621
|
+
|
|
622
|
+
**Intelligence & Analysis**
|
|
623
|
+
- `daily_briefing` — Executive summary of discoveries
|
|
624
|
+
- `trend_analysis` — Statistical patterns, anomalies, and predictions
|
|
625
|
+
- `get_actionable_signals` — Classify content into actionable signals with priority levels
|
|
626
|
+
- `signal_chains` — Get causal signal chains connecting related events over time
|
|
627
|
+
- `semantic_shifts` — Detect narrative shifts in topics you follow
|
|
628
|
+
- `topic_connections` — Build knowledge graphs from content
|
|
629
|
+
|
|
630
|
+
**Developer Context**
|
|
631
|
+
- `get_context` — Get user's interests, tech stack, learned affinities
|
|
632
|
+
- `context_analysis` — Optimize your context for better relevance
|
|
633
|
+
- `knowledge_gaps` — Detect knowledge gaps in your project dependencies
|
|
634
|
+
- `project_health` — Project health radar for dependency freshness and security
|
|
635
|
+
- `reverse_mentions` — Find where your projects are mentioned in sources
|
|
636
|
+
- `attention_report` — Analyze attention allocation vs codebase needs
|
|
637
|
+
- `developer_dna` — Export your Developer DNA — tech identity, dependencies, engagement, blind spots
|
|
638
|
+
|
|
639
|
+
**Decision & Memory**
|
|
640
|
+
- `decision_memory` — Manage developer decisions (record, list, check, update, supersede)
|
|
641
|
+
- `tech_radar` — Generate tech radar from decisions and content signals
|
|
642
|
+
- `check_decision_alignment` — Check if a technology aligns with active decisions
|
|
643
|
+
- `decision_windows` — View time-bounded opportunities requiring attention
|
|
644
|
+
- `compound_advantage` — Measures intelligence leverage for decisions
|
|
645
|
+
|
|
646
|
+
**Agent Integration**
|
|
647
|
+
- `agent_memory` — Cross-agent persistent memory — store and recall across sessions
|
|
648
|
+
- `agent_session_brief` — Tailored session startup context for AI agents
|
|
649
|
+
- `delegation_score` — Should the agent proceed or ask the human?
|
|
650
|
+
- `export_context_packet` — Generate portable context packet for session handoff
|
|
651
|
+
|
|
652
|
+
**System**
|
|
653
|
+
- `source_health` — Diagnose source fetching and data quality issues
|
|
654
|
+
- `config_validator` — Validate configuration and detect issues
|
|
655
|
+
- `llm_status` — Check LLM/Ollama configuration and availability
|
|
656
|
+
- `autophagy_status` — Intelligence metabolism status — calibration accuracy, anti-patterns
|
|
657
|
+
|
|
658
|
+
### Features
|
|
659
|
+
|
|
660
|
+
- 11 content sources: Hacker News, Reddit, Twitter/X, GitHub, RSS, YouTube, arXiv, Dev.to, Lobsters, Product Hunt, custom feeds
|
|
661
|
+
- PASIFA scoring algorithm — 5-axis codebase-aware relevance with confidence calibration
|
|
662
|
+
- Privacy-first — local SQLite reads; the only outbound call is vulnerability_scan (package names + versions to OSV.dev), zero telemetry
|
|
663
|
+
- BYOK — bring your own API keys, never stored remotely
|
|
664
|
+
- Works offline with Ollama fallback for embeddings
|
|
665
|
+
- Dual transport: stdio (default) and Streamable HTTP
|
|
666
|
+
- SQLite storage with automatic migrations
|
|
667
|
+
- Compatible with Claude Code, Cursor, Windsurf, VS Code Copilot, and any MCP client
|