viafrei 1.3.15 → 1.3.22
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/API.md +623 -0
- package/CHANGELOG.md +452 -0
- package/LICENSE +2 -1
- package/NOTICE +23 -7
- package/README.md +41 -8
- package/SOURCES.md +95 -16
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,455 @@
|
|
|
3
3
|
All notable changes to this package are documented here. The format follows Keep
|
|
4
4
|
a Changelog and the versions follow Semantic Versioning.
|
|
5
5
|
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
Nothing yet.
|
|
9
|
+
|
|
10
|
+
## [1.3.22] - 2026-09-28
|
|
11
|
+
|
|
12
|
+
**A fresh snapshot of the production server, and the version number that goes with it.
|
|
13
|
+
Nothing else, and the diff is the evidence: outside this entry the release is nine
|
|
14
|
+
insertions and nine deletions, every one of them a version string or a date** — four in
|
|
15
|
+
`API.md`, two in the snapshot, one in the manifest and two in the lockfile.
|
|
16
|
+
|
|
17
|
+
The service moved from 1.3.16 to 1.3.22 in six patch releases while this package sat at
|
|
18
|
+
1.3.16 — one of which carried no runtime code and was never deployed, so five
|
|
19
|
+
deployments. **None of them changed the LISTED surface**: the tools, resources, templates
|
|
20
|
+
and prompts a client is offered, which is what this package documents and all a list
|
|
21
|
+
method can show. It is not a claim about what a read returns, and one of the five did
|
|
22
|
+
change that — 1.3.19 corrected an attribution resource's contents. That is why nothing in
|
|
23
|
+
`API.md` moves except its header. Measured rather than assumed: the live server was asked to
|
|
24
|
+
describe itself again and the answer was compared, field by field, against the snapshot
|
|
25
|
+
shipped in 1.3.16 — every tool name, title, description and annotation, every input
|
|
26
|
+
schema including each parameter's type, bounds and pattern, all ten resources, both
|
|
27
|
+
resource templates, all nine prompts, the server's own instructions, and the advertised
|
|
28
|
+
capabilities. **Zero differences.** The five deployed releases were server-side data and
|
|
29
|
+
rendering fixes: a Bundesland decided by the order map extracts had been loaded in, an
|
|
30
|
+
attribution resource that claimed we hold nothing from a source we serve, a batch of
|
|
31
|
+
defects closing the 1.3 milestone, and a place answer for "Munich" restored. The sixth,
|
|
32
|
+
1.3.17, says in its own block that it carries no runtime code and is not deployed.
|
|
33
|
+
|
|
34
|
+
So this release is worth exactly one thing to a reader, and it is worth being plain about
|
|
35
|
+
which: the document in the package now says it was captured on 2026-09-28 from server
|
|
36
|
+
1.3.22, rather than on 2026-09-27 from 1.3.16 — one day and six version numbers. A dated
|
|
37
|
+
snapshot whose version is behind invites the reader to wonder what has changed since, and
|
|
38
|
+
here the answer is nothing, which they can only know if the snapshot says so.
|
|
39
|
+
|
|
40
|
+
**No behaviour changes.** `dist/` is built rather than committed and no file under `src/`
|
|
41
|
+
has changed since the 1.3.16 tag, which is the evidence for the claim. No flag, default
|
|
42
|
+
or exit code moves. Two of the seven `files` entries change — `API.md` and
|
|
43
|
+
`CHANGELOG.md` — and the tarball still holds 21 paths.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- **`catalogue.json` re-captured** from the production server on 2026-09-28 over protocol
|
|
48
|
+
`2025-06-18`: `initialize` plus `tools/list`, `resources/list`,
|
|
49
|
+
`resources/templates/list` and `prompts/list`. **No tool was invoked**, so no upstream
|
|
50
|
+
provider was contacted — listing is metadata, calling is traffic, and one provider
|
|
51
|
+
behind this service puts the access itself at risk if queried needlessly. The same two
|
|
52
|
+
substitutions its own `$comment` documents were applied again and asserted rather than
|
|
53
|
+
trusted: 18 per-tool `$schema` declarations dropped, and the two 288-character
|
|
54
|
+
ISO-8601 date patterns stored as their length, at `get_train_departures.when` and
|
|
55
|
+
`watch_situation.until`. Both counts were asserted by the one-off script that made the
|
|
56
|
+
capture, which refused to write the file unless they came out exactly so — **not** by
|
|
57
|
+
anything this repository carries. An earlier draft of this sentence said "the capture is
|
|
58
|
+
refused", present tense, which reads as a standing property of the tooling and would
|
|
59
|
+
send a reader looking for a gate that is not there. There is no capture script here, and
|
|
60
|
+
re-capturing is a deliberate act performed by hand.
|
|
61
|
+
|
|
62
|
+
- **`API.md` regenerated**, which under `npm run check:docs` it has to be. The only lines
|
|
63
|
+
that differ are the capture date in the header paragraph, the server version in the
|
|
64
|
+
table, the captured-from line, and the footer — because the server said the same thing
|
|
65
|
+
it said the day before.
|
|
66
|
+
|
|
67
|
+
### A note on version matching, because 1.3.16 made a promise this release cannot keep
|
|
68
|
+
|
|
69
|
+
1.3.16 argued its number should match the running service so that "somebody comparing the
|
|
70
|
+
two now reads one number instead of wondering which is behind". That argument does not
|
|
71
|
+
survive contact with how fast the service ships: production went 1.3.16 → 1.3.18 → 1.3.22
|
|
72
|
+
in under two hours, twice while this release was being measured. A package cannot track
|
|
73
|
+
that, and pretending otherwise means every publish is stale on arrival.
|
|
74
|
+
|
|
75
|
+
What this package can honestly say is what it now says: the snapshot carries the version
|
|
76
|
+
and date of the server it was taken from, and the document names the running server as the
|
|
77
|
+
source of truth for anything newer. The numbers agree today because this release chose
|
|
78
|
+
once more to make them agree — it stepped over 1.3.17 to 1.3.21 to land on production's
|
|
79
|
+
number, which a reader comparing this version with the previous one in the registry can
|
|
80
|
+
see for themselves. Calling that a coincidence would be the same overclaim in a smaller
|
|
81
|
+
font. It is the last time alignment is a reason to cut a release: from here the snapshot's
|
|
82
|
+
own version and date carry that information, and no release should be cut for the sole
|
|
83
|
+
purpose of making the numbers agree.
|
|
84
|
+
|
|
85
|
+
## [1.3.16] - 2026-09-27
|
|
86
|
+
|
|
87
|
+
**This is the release that delivers the licence corrections to the people the
|
|
88
|
+
licences point at.** `NOTICE` is the file Apache-2.0 § 4(d) makes every downstream
|
|
89
|
+
redistributor carry, and until this publish the corrected text existed only in the
|
|
90
|
+
repository: the 1.3.15 tarball on the registry still carries the previous wording. So
|
|
91
|
+
publishing is not a side effect of the correction, it **is** the correction — which
|
|
92
|
+
is the whole reason this release exists, because nothing in `dist/` changes.
|
|
93
|
+
|
|
94
|
+
The number matches the running service rather than counting the changes here.
|
|
95
|
+
Production answered `initialize` with `1.3.16` when it was asked on 2026-09-27, and
|
|
96
|
+
this package is the bridge to that server, so somebody comparing the two now reads
|
|
97
|
+
one number instead of wondering which is behind.
|
|
98
|
+
|
|
99
|
+
**No behaviour changes.** `dist/` is built rather than committed, and no file under
|
|
100
|
+
`src/` has changed since the 1.3.15 tag — which is the evidence for the claim, since
|
|
101
|
+
a diff of an untracked directory would be no evidence at all. So no flag, default or
|
|
102
|
+
exit code moves. **Six** of the seven `files` entries do change —
|
|
103
|
+
`README.md`, `LICENSE`, `NOTICE`, `SOURCES.md`, `CHANGELOG.md` and the new
|
|
104
|
+
`API.md` — and the tarball goes from twenty paths to twenty-one. (Six *entries*,
|
|
105
|
+
not six files: `dist` is a directory.)
|
|
106
|
+
|
|
107
|
+
This paragraph has now been wrong twice, which is worth leaving on the record
|
|
108
|
+
rather than tidying away. The first draft called these "the repository's own
|
|
109
|
+
development scripts" and said the next tarball would differ in two files — true of
|
|
110
|
+
the first change here, false once the licence work landed beside it. The second
|
|
111
|
+
draft said **four** files and omitted `LICENSE` — and the commit that wrote that
|
|
112
|
+
sentence is the same commit that changed `LICENSE`, so it was false at the moment
|
|
113
|
+
it was written, in the paragraph written to correct a false count. The count moved
|
|
114
|
+
once more at the cut, because `API.md` joined `files` in this release. Every
|
|
115
|
+
version of it has been computed from `package.json`'s `files` intersected with
|
|
116
|
+
`git diff --name-only v1.3.15..HEAD`, with the path count from `npm pack --json`,
|
|
117
|
+
rather than counted by eye — which is the only way this sentence has ever been
|
|
118
|
+
right.
|
|
119
|
+
|
|
120
|
+
### Added
|
|
121
|
+
|
|
122
|
+
- **A sweep that keeps the twenty-first call site from being written by accident**
|
|
123
|
+
(`scripts/tools.test.mjs`, `npm run test:tools`, and a step in CI). Eighteen
|
|
124
|
+
cases: what `resolveTool` accepts and refuses, that its directory list is
|
|
125
|
+
root-owned and not group- or other-writable (the property the module relies on,
|
|
126
|
+
rather than the list that is supposed to have it), that its contents cannot be
|
|
127
|
+
extended at runtime, that an `npm_execpath` which is absolute, real and readable
|
|
128
|
+
but not npm is refused, and then a sweep of all thirty-two source files,
|
|
129
|
+
walked recursively, for a spawn whose program is a bare quoted name.
|
|
130
|
+
|
|
131
|
+
It carries three preconditions, because a gate whose input is absent reports
|
|
132
|
+
success about what it never read: **every** source root must have contributed a
|
|
133
|
+
file and an unreadable root is a failure rather than an absence; the expression
|
|
134
|
+
must locate a program argument in a real file of this repository, proved by
|
|
135
|
+
putting a real call's program back to a literal in memory and requiring it to be
|
|
136
|
+
found; and it must go red on a planted bad call, with the fixtures assembled at
|
|
137
|
+
runtime so no literal in this file can satisfy its own sweep.
|
|
138
|
+
|
|
139
|
+
Both of the last two exist because the first drafts did not do what their own
|
|
140
|
+
comments claimed. The floor was a floor on the *sum*, and `scripts` and `test`
|
|
141
|
+
clear it between them — so `src/` could be deleted entirely and the run still
|
|
142
|
+
printed ok at 21 files. And the "it can see a call" precondition evaluated the
|
|
143
|
+
real expression only on the negative case; the positive half used a different,
|
|
144
|
+
simpler pattern and never asked the real one to read a file.
|
|
145
|
+
|
|
146
|
+
Proved the way a gate has to be: one real call site reverted to a bare name
|
|
147
|
+
turns the sweep red, one source root removed turns precondition 1 red, and the
|
|
148
|
+
files were restored byte-identical afterwards.
|
|
149
|
+
|
|
150
|
+
- **[API.md](API.md): a reference for all 18 tools, generated rather than written.**
|
|
151
|
+
`catalogue.json` is what the production server answered when it was asked to
|
|
152
|
+
describe itself — `initialize` plus `tools/list`, `resources/list`,
|
|
153
|
+
`resources/templates/list` and `prompts/list`, captured on 2026-09-27 from
|
|
154
|
+
server `1.3.16`. `scripts/gen-api-doc.mjs` renders the document from it
|
|
155
|
+
(`npm run docs:api`), and `npm run check:docs` in CI fails if the two have
|
|
156
|
+
drifted. Every tool description in it is the server's own text, verbatim,
|
|
157
|
+
because that text is what an assistant reads when it decides which tool to
|
|
158
|
+
call — paraphrasing it would document a different server.
|
|
159
|
+
|
|
160
|
+
**No tool was invoked to produce the snapshot.** Listing is metadata; calling is
|
|
161
|
+
traffic, and one of the providers behind this service sets a floor on how often a
|
|
162
|
+
station may be queried, with the access itself at risk if it is exceeded. The
|
|
163
|
+
capture is therefore five list methods and nothing else.
|
|
164
|
+
|
|
165
|
+
**What generating it does and does not fix**, because README.md already argued
|
|
166
|
+
the opposite case and that argument was right. Drift between the document and the
|
|
167
|
+
snapshot is now impossible to keep — CI regenerates and compares. Drift between
|
|
168
|
+
the snapshot and the live server is not fixed by anything, because a capture is a
|
|
169
|
+
point in time. So API.md's own header says it is a dated snapshot, carries the
|
|
170
|
+
date, and names the running server as the source of truth — in that file and not
|
|
171
|
+
only in README.md. Both of them ship in the tarball, so that is not the reason;
|
|
172
|
+
the reason is that a qualification has to travel with the document it qualifies,
|
|
173
|
+
because somebody who opens the catalogue to look up a parameter has no occasion
|
|
174
|
+
to read the page beside it.
|
|
175
|
+
|
|
176
|
+
Two substitutions in the snapshot, both recorded in its own `$comment` rather
|
|
177
|
+
than left as silent differences from what the server sent: the 18 per-tool
|
|
178
|
+
`$schema` declarations are dropped as one constant repeated 18 times, and two
|
|
179
|
+
288-character date patterns are stored as their LENGTH. The second was forced by
|
|
180
|
+
the leak sweep and the interesting part is which side gave way — such a regex
|
|
181
|
+
spells its arithmetic as character classes of selected digits, which a digit-run
|
|
182
|
+
scanner cannot tell from a five-digit internal value. Both remedies on the
|
|
183
|
+
sweep's side would have been falsehoods: narrowing the scanner weakens it for
|
|
184
|
+
every file, and an allow-list entry would record that a character class is a
|
|
185
|
+
number this project publishes. So the text that cannot be scanned is not stored.
|
|
186
|
+
Nothing is hidden by it — the document already summarised a pattern over 60
|
|
187
|
+
characters by its length, and the server hands anyone the full expression.
|
|
188
|
+
|
|
189
|
+
One parameter is an object whose seven keys each carry their own bounds, and the
|
|
190
|
+
first draft rendered it as a dash in both the default and the constraints
|
|
191
|
+
column — the table's strongest claim broken on the row with the most to say. The
|
|
192
|
+
cause defeated the safety net as well: `properties` sat in the set of keywords
|
|
193
|
+
the renderer treats as handled, so the fallback that lists an unrecognised
|
|
194
|
+
keyword as a bare name never fired. The keyword was known; it was simply never
|
|
195
|
+
rendered.
|
|
196
|
+
|
|
197
|
+
- **A self-test for the API-reference generator** (`scripts/gen-api-doc.test.mjs`,
|
|
198
|
+
`npm run test:docs`, and a step in CI). Its cases include the drift check refusing a
|
|
199
|
+
hand-edited file, never writing during `--check`, and naming `docs:api` when the
|
|
200
|
+
document is absent; eight snapshot mutations each refused with a named reason; a
|
|
201
|
+
malformed `required` rendering rather than throwing; a planted nested `default`
|
|
202
|
+
reaching the document; a union type in a table cell and in a bullet; an
|
|
203
|
+
array-of-scalar; and the reported line count agreeing with `wc -l`. The run prints
|
|
204
|
+
the total, which is the number to trust — this file has been wrong about counts
|
|
205
|
+
more than once, so it states none here.
|
|
206
|
+
|
|
207
|
+
It exists because the generator was the only script here making claims with nothing
|
|
208
|
+
checking them, and the same six mutants were being re-run by hand across three
|
|
209
|
+
review rounds — a check performed by remembering is not a check. It also earned
|
|
210
|
+
itself immediately, by catching two defects nothing else could:
|
|
211
|
+
|
|
212
|
+
The whitespace-flattening expression, rewritten to remove a super-linear
|
|
213
|
+
backtracking pattern, **was not equivalent to what it replaced.** It handled only
|
|
214
|
+
spaces and tabs beside the newline, so a `\r\n` line ending would have left a stray
|
|
215
|
+
carriage return in the document. API.md regenerated byte-identical, `--check`
|
|
216
|
+
passed, every gate was green — because this snapshot contains no CRLF. An output
|
|
217
|
+
comparison can only speak about the input it was given, so the test compares the two
|
|
218
|
+
**expressions** over every string up to length four drawn from a whitespace-heavy
|
|
219
|
+
alphabet, plus random longer ones, and asserts first that the alphabet can expose
|
|
220
|
+
the bug that shipped.
|
|
221
|
+
|
|
222
|
+
And a **union type was escaped twice**: `typeOf` joined with an already-escaped pipe
|
|
223
|
+
and the cell renderer escaped that pipe again, giving `string \\| null` — a literal
|
|
224
|
+
backslash, and a bare pipe left to end the table row early. In a bullet, which is not
|
|
225
|
+
a table, it produced a stray backslash instead. No tool in this snapshot declares a
|
|
226
|
+
union type, so neither was reachable and no comparison of documents could have found
|
|
227
|
+
it. Escaping now happens in one place, the one that knows it is writing a table cell.
|
|
228
|
+
|
|
229
|
+
- **[SUPPORT.md](SUPPORT.md)**, so GitHub's issue chooser has somewhere to point:
|
|
230
|
+
where a question, a wrong answer and a security report each go, and what makes a
|
|
231
|
+
report actionable.
|
|
232
|
+
|
|
233
|
+
- **README gains a Documentation table and five worked use cases** — a motorway
|
|
234
|
+
briefing, a broken commute including a station lift that is out, an EV weekend, a
|
|
235
|
+
dispatcher's morning brief, and a local-guide agent — each named by the question
|
|
236
|
+
it answers rather than by the tools it calls.
|
|
237
|
+
|
|
238
|
+
### Changed
|
|
239
|
+
|
|
240
|
+
- **One entry of 13 characters left the leak sweep's private-name list, under that
|
|
241
|
+
list's own rule 1.** The rule is stated in `scripts/rules.json`: an entry must not
|
|
242
|
+
be a substring of text this repository legitimately prints, because such an entry
|
|
243
|
+
can never be satisfied, and the only ways out are deleting it or narrowing the
|
|
244
|
+
scanner — which is strictly worse. There is no mechanical test for it; the sweep
|
|
245
|
+
going red *is* the test, and it went red. Declared narrowing: one spelling of 13
|
|
246
|
+
characters is no longer matched anywhere. The list's second rule is not engaged,
|
|
247
|
+
which decides that nothing else follows: the audit recorded in that file says
|
|
248
|
+
nothing on the list is from the class whose harm is confirming a guess —
|
|
249
|
+
credentials, tokens, session or contract identifiers, access-granting hostnames,
|
|
250
|
+
personal data — so there is no rotation and no rename here.
|
|
251
|
+
|
|
252
|
+
Recorded that way on purpose, and it is a change of practice rather than of
|
|
253
|
+
style. The two removals recorded under 0.0.9 described what the entries were
|
|
254
|
+
ABOUT, and taken together those descriptions narrowed the candidate space for a
|
|
255
|
+
live entry further than a hash does — the same caption failure the number
|
|
256
|
+
allow-list refuses on the facing page. The file now ends with the ruling: record
|
|
257
|
+
the rule, the lengths and the narrowing, never the subject. This is the first
|
|
258
|
+
entry written under it. The older wordings stay where they are, because editing
|
|
259
|
+
a published file does not unpublish it.
|
|
260
|
+
|
|
261
|
+
Coverage was asked of the change rather than asserted, since going from six
|
|
262
|
+
entries to five must not leave the sweep reporting PASS about what it no longer
|
|
263
|
+
looks for. The matcher was exercised per slot without needing any real name:
|
|
264
|
+
the list replaced by five planted names, each planted in text, five reds
|
|
265
|
+
required, and a negative control that stays clean. The sweep also prints the
|
|
266
|
+
list's size on every run, so the change is visible rather than silent, and the
|
|
267
|
+
gate self-test still refuses an emptied list. The window `minTokenLength` and
|
|
268
|
+
`maxTokenLength` is unchanged at 7 and 15: both are stored literals, neither is
|
|
269
|
+
derived from the list, and the removed entry sat at neither bound, so no
|
|
270
|
+
published number narrowed.
|
|
271
|
+
|
|
272
|
+
- **`numbers.allowed` admits four values the SERVER publishes about itself** — two
|
|
273
|
+
inside tool descriptions and two as bounds in its own input schemas — under one
|
|
274
|
+
general rule written into that file rather than a caption each, because a caption
|
|
275
|
+
per value is the construction the list exists to avoid. It is safe to state in
|
|
276
|
+
general terms because the sweep already refuses an allowed number that occurs
|
|
277
|
+
nowhere in the tree, so an exemption cannot outlive its reason.
|
|
278
|
+
|
|
279
|
+
- **Four statements about other people's licences were wrong, and they are the kind
|
|
280
|
+
a reader acts on.** Every one was verified against its own source before it was
|
|
281
|
+
changed, and each correction says that an earlier version had it wrong rather than
|
|
282
|
+
quietly reading better.
|
|
283
|
+
- **Share-alike reaches adaptations, not aggregations.** `SOURCES.md`, `NOTICE`
|
|
284
|
+
and `README.md` all said DELFI data must not be blended into a result under a
|
|
285
|
+
different licence. CC BY-SA 4.0 art. 3(b) is expressed only over Adapted
|
|
286
|
+
Material (art. 1(a)); showing licensed data beside another source's data is an
|
|
287
|
+
aggregation, and Creative Commons states in terms that the condition "applies
|
|
288
|
+
only for works considered adaptations under copyright law, not simply in
|
|
289
|
+
collections with other works". Worse than generous in two ways: art. 3(b)(3)
|
|
290
|
+
forbids imposing terms that restrict rights the licence grants, which is what
|
|
291
|
+
telling you an aggregation is forbidden does — and the rule as written condemned
|
|
292
|
+
this service, since a weather answer can name `["dwd","osm"]`.
|
|
293
|
+
- **The DELFI licence version was sourced to nothing.** Measured at both levels
|
|
294
|
+
on 2026-09-27: the GovData record for the realtime feed carries the unversioned
|
|
295
|
+
licence URI and an empty dataset-level licence, and the national access point's
|
|
296
|
+
own metadata reports the same unversioned term. The publisher's sibling feeds in
|
|
297
|
+
the same catalogue *are* versioned, so it states a version when it means one.
|
|
298
|
+
The page now names the family, shows the evidence, and says to treat the
|
|
299
|
+
share-alike as applying regardless — because the version decides what a
|
|
300
|
+
recipient may put on a derivative (art. 3(b)(1)), and 3.0 unported has no
|
|
301
|
+
express database-rights clause where 4.0 art. 4 does.
|
|
302
|
+
- **§ 7 DWD-Gesetz prescribes a duty, not a wording.** Fetched verbatim: the
|
|
303
|
+
section is headed *Quellenschutz*, requires distribution to be "nur unter
|
|
304
|
+
Angabe der Quelle zulässig" and sets no text — and its second sentence adds
|
|
305
|
+
that fuller protection under the Urheberrechtsgesetz "bleibt davon unberührt",
|
|
306
|
+
so attribution is the statute's minimum rather than the whole of what may be
|
|
307
|
+
owed. The three words come from the DWD's own guidance, which also permits the
|
|
308
|
+
logo form — so a reader told the statute fixes the characters might refuse a
|
|
309
|
+
form the publisher expressly allows.
|
|
310
|
+
- **`NOTICE` understated the ODbL duty, and it is the file that republishes
|
|
311
|
+
itself** (Apache-2.0 § 4(d) makes every downstream redistributor carry it). It
|
|
312
|
+
said "address results" where the predicate is which *table* answered — place
|
|
313
|
+
resolution falls through the gazetteer to the OSM tables, so any answer about a
|
|
314
|
+
place may be OSM-derived — and offered one extract where the § 4.6 offer covers
|
|
315
|
+
both addresses and points of interest.
|
|
316
|
+
|
|
317
|
+
### Fixed
|
|
318
|
+
|
|
319
|
+
- **Every external program these scripts run is now resolved to an absolute path
|
|
320
|
+
instead of being looked up on `$PATH`** (`scripts/tools.mjs`). `git`, `tar`,
|
|
321
|
+
`npm` and a `mkdir` were spawned by bare name, which means the environment — not
|
|
322
|
+
this repository — decided which program actually ran. That matters more here
|
|
323
|
+
than it would elsewhere: one of these scripts is the leak sweep that decides
|
|
324
|
+
whether a commit may be published, and another is the hygiene gate that reads
|
|
325
|
+
the tarball about to be uploaded to the registry. A gate whose implementation
|
|
326
|
+
the caller can substitute is not a gate. SonarCloud reported seven of the call
|
|
327
|
+
sites as `javascript:S4036` and the project's Security Rating on new code stood
|
|
328
|
+
at B because of them.
|
|
329
|
+
- `git` and `tar` now come from `/usr/bin` or `/bin` only. `/usr/local/bin` and
|
|
330
|
+
`/opt/homebrew/bin` are deliberately not searched: they are writable by the
|
|
331
|
+
logged-in user on a normal developer machine, so admitting them would
|
|
332
|
+
reinstate the substitution this change removes. A tool that is genuinely
|
|
333
|
+
elsewhere makes the scripts refuse and say where they looked, which is a
|
|
334
|
+
better failure than quietly running something else.
|
|
335
|
+
- `npm` is no longer treated as a program at all. It is a JavaScript file, so it
|
|
336
|
+
is run as `<absolute node> <absolute npm-cli.js>`; node's own path is
|
|
337
|
+
`process.execPath`, which nothing can substitute. `mkdir` was replaced by
|
|
338
|
+
`fs.mkdirSync` — no subprocess at all.
|
|
339
|
+
- **Twenty call sites changed, not the seven that were reported.** The other
|
|
340
|
+
thirteen are in the two self-tests, which SonarCloud does not analyse. Leaving
|
|
341
|
+
them would have left the rule true of the code and false of the repository,
|
|
342
|
+
and a rule with a quiet exemption is the one nobody remembers when adding the
|
|
343
|
+
next call. (Counted per file in the finished tree: `check-leaks.mjs` 2,
|
|
344
|
+
`check-tarball.mjs` 4, `npm-pack-json.mjs` 1 — Sonar's seven — then
|
|
345
|
+
`check-leaks.test.mjs` 3 and `check-tarball.test.mjs` 10. The first version of
|
|
346
|
+
this entry said nineteen, because it was counted with a single-line grep that
|
|
347
|
+
cannot see the one call whose program argument sits on its own line. A count
|
|
348
|
+
taken with the wrong instrument, in a release whose own subject is exactly
|
|
349
|
+
that.)
|
|
350
|
+
|
|
351
|
+
- **And the repair for that duplicated it, which the quality gate caught before
|
|
352
|
+
the merge.** The precondition was *copied* from one self-test into the other —
|
|
353
|
+
eleven lines — and SonarCloud failed the pull request on **3.1% duplication on
|
|
354
|
+
new code** against a 3% limit, over exactly that block. Copying was the wrong
|
|
355
|
+
half of the right idea: the answer was always one implementation used twice.
|
|
356
|
+
It now lives in `scripts/fixture-root.mjs` as `missingFixtureImports()`, and each
|
|
357
|
+
self-test keeps its own refusal wording, because the two name different builders
|
|
358
|
+
and exit by different routes — a difference that is real rather than incidental.
|
|
359
|
+
Re-proved in each: dropping `tools.mjs` from a caller's file list makes that file
|
|
360
|
+
refuse by name, and each names its own builder.
|
|
361
|
+
|
|
362
|
+
**Concentrating the guarantee doubled its blast radius, so it got the assertion
|
|
363
|
+
it never had.** One function now stands behind every self-test that uses it, so a
|
|
364
|
+
silent `return []` disarms all of them at once and restores the wrong-reason pass
|
|
365
|
+
that started this thread — a sweep that cannot start, reporting no findings. The
|
|
366
|
+
number of those callers is deliberately not written here or in the module: it grew
|
|
367
|
+
again inside this release, and the sentence that said "both" went stale unnoticed
|
|
368
|
+
in five places while the corrected wording lived in one. On an ordinary run they
|
|
369
|
+
only ever exercise the complete-fixture path, so
|
|
370
|
+
until now the "missing" branch was proved solely by hand-mutating a file list:
|
|
371
|
+
four times by two people, and never again by anything. Two cases cover both
|
|
372
|
+
directions on a temporary directory, and they are mutation-proved — a planted
|
|
373
|
+
`return []` reddens one, and ignoring the directory argument reddens both.
|
|
374
|
+
|
|
375
|
+
Worth recording as the shape rather than the incident. A missing precondition was
|
|
376
|
+
fixed by adding one; adding it introduced a duplicate of it; the gate caught the
|
|
377
|
+
duplicate. Three links, and every one of them was found by something other than
|
|
378
|
+
the test suite, which was green at each step. The file count in this entry moved
|
|
379
|
+
from twenty-eight to twenty-nine because of it, then to thirty when this release
|
|
380
|
+
added a source file of its own, and then to **thirty-two** as it added the generator's
|
|
381
|
+
self-test and the module they share. The first two were re-derived from `npm run test:tools` rather than
|
|
382
|
+
incremented by hand. The third was not, and the review round found it stale. The
|
|
383
|
+
fourth was not typed either: it was read out of `npm run test:tools`'s own output
|
|
384
|
+
and the edit refused to write a number the command did not report. That was a
|
|
385
|
+
one-off script in a scratchpad, not something this repository carries — said plainly
|
|
386
|
+
because an earlier draft of this very sentence claimed a committed artefact that
|
|
387
|
+
does not exist. This paragraph has been wrong before, and that was the first time
|
|
388
|
+
it invented an artefact rather than a number.
|
|
389
|
+
|
|
390
|
+
- **The leak sweep's own self-test had no precondition on the fixture it builds,
|
|
391
|
+
and reported a scope regression instead.** Both self-tests copy a named list of
|
|
392
|
+
files into a throwaway repository, and `tools.mjs` was missing from both lists.
|
|
393
|
+
`check-tarball.test.mjs` refused by name, which is what a precondition is for.
|
|
394
|
+
`check-leaks.test.mjs` had no such check: **measured**, three of its four cases
|
|
395
|
+
failed with messages about scope — "expected a clean exit, got 1", "the run does
|
|
396
|
+
not say which scope it used" — because every invocation died of
|
|
397
|
+
`ERR_MODULE_NOT_FOUND`, and the fourth case *passed*, since a sweep that cannot
|
|
398
|
+
start also cannot report a finding. That is worse than a red suite: it sends the
|
|
399
|
+
next reader after the ruleset instead of after a missing file. It now refuses by
|
|
400
|
+
name, proved by dropping the file again.
|
|
401
|
+
|
|
402
|
+
- **`npm_execpath` was trusted if it was merely absolute and ended in `.js`** —
|
|
403
|
+
which reversed this change's own thesis for npm. The decider had moved from
|
|
404
|
+
`$PATH` to an environment variable, and the local review demonstrated it by
|
|
405
|
+
pointing the variable at a hand-written file, which the tarball gate would then
|
|
406
|
+
have run as npm. The value must now also be *shaped* like npm's CLI, ending in
|
|
407
|
+
`node_modules/npm/bin/npm-cli.js`. What that does not claim, because a security
|
|
408
|
+
note that overstates its reach is worse than none: anyone who can both set your
|
|
409
|
+
environment and create a file at that path is still obeyed — and anyone able to
|
|
410
|
+
do both can usually substitute node itself. The narrowing is from "any writable
|
|
411
|
+
path" to "a path that looks like a real npm installation": **it stops accidents,
|
|
412
|
+
not an attacker**, and it is not a privilege barrier. An earlier draft said
|
|
413
|
+
"stray, mistaken or opportunistic", which the sentence after it contradicted — an
|
|
414
|
+
opportunistic value costs one `mkdir -p`.
|
|
415
|
+
|
|
416
|
+
- **`npmCliPath()` refused to find npm on a Homebrew Mac.** Its first draft knew
|
|
417
|
+
only the `../lib/node_modules/…` layout, which is what the GitHub-hosted runner
|
|
418
|
+
and nvm use — so it passed in CI and failed on a developer's machine, where
|
|
419
|
+
Homebrew puts npm under `../libexec/lib/node_modules/…`. Both layouts are tried
|
|
420
|
+
now, each from the given path and again through `realpathSync`, since a node
|
|
421
|
+
reached by a symlink resolves its siblings from the real location. Caught by the
|
|
422
|
+
new self-test on the first run, which is the argument for having written it.
|
|
423
|
+
|
|
424
|
+
- **The false-positive fix opened a worse false negative, and the second review
|
|
425
|
+
round caught it.** Excluding `RE.exec('git')` by putting a `(?<!\.)` lookbehind
|
|
426
|
+
in front of the whole alternation also excluded every *member-expression* spawn —
|
|
427
|
+
`child_process.execFileSync('git', …)`, `cp.execSync('git status')` — which is a
|
|
428
|
+
shape SonarJS does report and a contributor can write without doing anything
|
|
429
|
+
unusual. So a fix aimed at a shape nothing writes blinded the sweep to a shape
|
|
430
|
+
people do. The lookbehind now applies to the bare name `exec` alone, measured
|
|
431
|
+
over twelve shapes: the all-names form was wrong on four of them, this one on
|
|
432
|
+
none. The one trade it still makes — `obj.exec('git')`, a method named `exec` on
|
|
433
|
+
something that is not a regular expression — is in the limits list, because no
|
|
434
|
+
expression can tell it from `RE.exec('git')` without a parser. Both directions
|
|
435
|
+
are pinned in the preconditions now rather than left incidental, since a review
|
|
436
|
+
round changed this behaviour by accident once already.
|
|
437
|
+
|
|
438
|
+
Two smaller things fell out of it. The comment describing the lookbehind said
|
|
439
|
+
`(?!\.)` where the code says `(?<!\.)` — a look*ahead* there would match nothing
|
|
440
|
+
useful, so it was the one comment in the file that would mislead somebody
|
|
441
|
+
"fixing" the code to match it. And the worked examples added to document the
|
|
442
|
+
twelve shapes turned the file red, because an example of a bare call, spelled as
|
|
443
|
+
one, *is* a bare call as far as the sweep is concerned; they carry no quote
|
|
444
|
+
characters now. The sweep catching its own documentation is the least ambiguous
|
|
445
|
+
evidence available that the member-expression form works.
|
|
446
|
+
|
|
447
|
+
- **Two documents that enumerate the gates had gone stale in the same commit that
|
|
448
|
+
added one.** `CONTRIBUTING.md` said "four more checks exist, and CI runs all
|
|
449
|
+
four" — five now, and the new one was missing from the block a contributor is
|
|
450
|
+
sent to, which also made the next paragraph's "a fifth command" read as a
|
|
451
|
+
contradiction. The pull-request checklist named two gates as "the
|
|
452
|
+
public-repository gates", so a contributor following it would not have run the
|
|
453
|
+
sweep that exists to catch exactly the call they might be adding.
|
|
454
|
+
|
|
6
455
|
## [1.3.15] - 2026-09-27
|
|
7
456
|
|
|
8
457
|
The first release with features in it since the bridge got code. Three
|
|
@@ -574,6 +1023,9 @@ for it, so the number is free; the bridge will use it when the platform does.
|
|
|
574
1023
|
commits, and a squash makes them unreachable from `main` - which would turn
|
|
575
1024
|
the check red on `main` for everybody, for something no contributor did.
|
|
576
1025
|
|
|
1026
|
+
[1.3.22]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.22
|
|
1027
|
+
[1.3.16]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.16
|
|
1028
|
+
[1.3.15]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.15
|
|
577
1029
|
[1.3.12]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.12
|
|
578
1030
|
[1.3.10]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.10
|
|
579
1031
|
[0.0.9]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v0.0.9
|
package/LICENSE
CHANGED
|
@@ -210,7 +210,8 @@ bridge in this repository.
|
|
|
210
210
|
|
|
211
211
|
Data obtained through the ViaFrei MCP server keeps its own provider licence and
|
|
212
212
|
is not relicensed by anything here. Several of those licences are share-alike
|
|
213
|
-
(DELFI public-transport data is
|
|
213
|
+
(DELFI public-transport data is Creative Commons Attribution-ShareAlike; its
|
|
214
|
+
catalogue entry states no version — see SOURCES.md) or purpose-limited (MTS-K fuel
|
|
214
215
|
prices are consumer information only, with no redistribution in any form,
|
|
215
216
|
aggregates included).
|
|
216
217
|
|
package/NOTICE
CHANGED
|
@@ -10,15 +10,31 @@ keeps its provider's own terms. Those terms travel with the answer, not with
|
|
|
10
10
|
this package, and several of them are share-alike or purpose-limited. In
|
|
11
11
|
particular:
|
|
12
12
|
|
|
13
|
-
- DELFI public-transport data is
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
- DELFI public-transport data is Creative Commons Attribution-ShareAlike. The
|
|
14
|
+
catalogue record for the realtime feed names no version (see SOURCES.md), so
|
|
15
|
+
treat the share-alike as applying and do not rely on a version for a
|
|
16
|
+
derivative. Share-alike reaches ADAPTATIONS, not aggregations: if you
|
|
17
|
+
recompute, reshape or rearrange the data you must license that under BY-SA -
|
|
18
|
+
art. 1(a) of the 4.0 text names material "translated, altered, arranged,
|
|
19
|
+
transformed, or otherwise modified", so a rearrangement is inside the
|
|
20
|
+
obligation and not outside it - but showing it beside another source's data
|
|
21
|
+
is an aggregation and puts no obligation on the other source. Which version
|
|
22
|
+
applies is the open question SOURCES.md sets out; the words above are quoted
|
|
23
|
+
from 4.0 because that is the text we read.
|
|
16
24
|
- MTS-K fuel prices (Tankerkönig) are consumer information only. No
|
|
17
25
|
redistribution in any form, aggregates and derived tables included.
|
|
18
|
-
- Address
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
to
|
|
26
|
+
- Address, point-of-interest and place results can be derived from
|
|
27
|
+
OpenStreetMap under the ODbL 1.0. What decides it is which TABLE answered,
|
|
28
|
+
not which tool you called: place resolution falls through our own gazetteer
|
|
29
|
+
to the OSM tables, so any answer about a place may be OSM-derived. Read
|
|
30
|
+
`_meta.sources` and the attribution line on the answer you actually got — an
|
|
31
|
+
OSM-derived result names `osm`. The share-alike is on the database (ODbL 4.4)
|
|
32
|
+
and not on the answer (ODbL 4.5(b)); the answer carries a notice instead
|
|
33
|
+
(ODbL 4.3). Our offer under ODbL 4.6 stands and covers BOTH extracts —
|
|
34
|
+
addresses and points of interest, one file each — plus our alterations to
|
|
35
|
+
them, under ODbL 1.0 and free of charge. Ask by opening an issue on this
|
|
36
|
+
repository, or by the e-mail address in the Impressum at
|
|
37
|
+
https://viafrei.de/impressum if you have no GitHub account.
|
|
22
38
|
- Autobahn GmbH, BKG, DWD, Deutsche Bahn, GeoNames and the AFIR charging
|
|
23
39
|
feeds each carry their own licence and attribution string.
|
|
24
40
|
|
package/README.md
CHANGED
|
@@ -97,11 +97,18 @@ lorry parking. The table said "car and lorry parking" until this release; it was
|
|
|
97
97
|
the same over-claim the Rail row carried about disruptions, and it is corrected here rather
|
|
98
98
|
than left for a user to discover.
|
|
99
99
|
|
|
100
|
-
**No tool names, descriptions or schemas are
|
|
101
|
-
This file is frozen inside a published tarball and cannot be corrected
|
|
102
|
-
release, so a copied catalogue would start rotting the first time a
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
**No tool names, descriptions or schemas are written by hand on this page, on
|
|
101
|
+
purpose.** This file is frozen inside a published tarball and cannot be corrected
|
|
102
|
+
without a release, so a hand-copied catalogue would start rotting the first time a
|
|
103
|
+
description changed on the server.
|
|
104
|
+
|
|
105
|
+
**[API.md](API.md) is the way round that, and it is honest about what it is.** It
|
|
106
|
+
is *generated* from [`catalogue.json`](catalogue.json) — a snapshot of what the
|
|
107
|
+
production server answered when asked to describe itself — and CI fails if the two
|
|
108
|
+
have drifted, so the document cannot quietly disagree with the snapshot. What that
|
|
109
|
+
does not fix is the snapshot ageing relative to the live server: a capture is a
|
|
110
|
+
point in time, and API.md's header carries the date it was taken. **The source of
|
|
111
|
+
truth is still the running server**: connect any MCP client and call `tools/list`.
|
|
105
112
|
(<https://viafrei.de> is the live national traffic digest, not a catalogue.)
|
|
106
113
|
|
|
107
114
|
## Connect in one line
|
|
@@ -147,6 +154,25 @@ Claude Desktop's `claude_desktop_config.json`:
|
|
|
147
154
|
|
|
148
155
|
Restart the client and ask it one of the questions above.
|
|
149
156
|
|
|
157
|
+
## Documentation
|
|
158
|
+
|
|
159
|
+
| | |
|
|
160
|
+
|---|---|
|
|
161
|
+
| **[API.md](API.md)** | Every tool with its parameters, types, defaults and constraints, plus the resources, resource templates and prompts. Generated from a dated snapshot of the running server, so the descriptions are the server's own words — which is what your assistant actually reads when it picks a tool. |
|
|
162
|
+
| **[Wiki](https://github.com/mavrovde/viafrei-bridge/wiki)** | The prose half: [connecting your assistant](https://github.com/mavrovde/viafrei-bridge/wiki/Connecting-your-assistant), [tools at a glance](https://github.com/mavrovde/viafrei-bridge/wiki/Tools-at-a-glance), the [roadmap](https://github.com/mavrovde/viafrei-bridge/wiki/Roadmap) and an [FAQ](https://github.com/mavrovde/viafrei-bridge/wiki/FAQ). |
|
|
163
|
+
| **[SOURCES.md](SOURCES.md)** | Every publisher, what it covers, its licence, and the attribution line to reproduce — including the conditions that are licence breaches rather than style problems. |
|
|
164
|
+
| **[SUPPORT.md](SUPPORT.md)** | Where a question, a bad answer or a security report should go, and what makes a report easy to act on. |
|
|
165
|
+
|
|
166
|
+
### Worked use cases
|
|
167
|
+
|
|
168
|
+
Five walkthroughs, each naming the tools that answer it and what comes back:
|
|
169
|
+
|
|
170
|
+
- [Driving Munich to Berlin](https://github.com/mavrovde/viafrei-bridge/wiki/Use-case-Driving-Munich-to-Berlin) — briefing a motorway run: several A-roads in one call, roadworks ahead, a fuel or charging stop, parking at the far end.
|
|
171
|
+
- [The commute that broke](https://github.com/mavrovde/viafrei-bridge/wiki/Use-case-The-commute-that-broke) — departures, regional disruption, and a station lift that is out, which is the difference between a step-free route existing and not.
|
|
172
|
+
- [An EV on a long weekend](https://github.com/mavrovde/viafrei-bridge/wiki/Use-case-An-EV-on-a-long-weekend) — charging by connector and power, low-emission-zone rules, what is around a stop.
|
|
173
|
+
- [Fleet and logistics briefings](https://github.com/mavrovde/viafrei-bridge/wiki/Use-case-Fleet-and-logistics-briefings) — a dispatcher's morning brief, watches that report a change instead of being polled, and the one licence rule that bites hardest here.
|
|
174
|
+
- [Building a local guide agent](https://github.com/mavrovde/viafrei-bridge/wiki/Use-case-Building-a-local-guide-agent) — a vague place to coordinates and back, and what OpenStreetMap's licence asks of you.
|
|
175
|
+
|
|
150
176
|
## Why build on it
|
|
151
177
|
|
|
152
178
|
- **One endpoint instead of a stack of integrations.**
|
|
@@ -286,9 +312,16 @@ licence breach rather than a style problem:
|
|
|
286
312
|
- **MTS-K fuel prices are consumer information only.** No redistribution in any
|
|
287
313
|
form — that includes aggregates, comparisons, price tables and anything
|
|
288
314
|
derived. Answer the person who asked; do not build a product out of it.
|
|
289
|
-
- **DELFI public-transport data is
|
|
290
|
-
|
|
291
|
-
|
|
315
|
+
- **DELFI public-transport data is Creative Commons
|
|
316
|
+
Attribution-ShareAlike.** Share-alike travels with anything you *derive* from
|
|
317
|
+
it — recompute it, reshape it, rearrange it, build a delay table out of it, and
|
|
318
|
+
that is Adapted Material you must license under BY-SA (art. 1(a) names material
|
|
319
|
+
"translated, altered, arranged, transformed, or otherwise modified"). Merely **showing** it beside
|
|
320
|
+
another source's data is an aggregation, and puts no obligation on the other
|
|
321
|
+
source; an earlier version of this page said otherwise, which told you a
|
|
322
|
+
licence forbids something it permits. The catalogue record for the realtime
|
|
323
|
+
feed names no licence version, so do not rely on one for a derivative —
|
|
324
|
+
[SOURCES.md](SOURCES.md) has the detail and the open question.
|
|
292
325
|
|
|
293
326
|
Everything else — where each answer comes from, and what each licence asks of
|
|
294
327
|
you — is in [SOURCES.md](SOURCES.md). See also [NOTICE](NOTICE) and
|