The v0.12.0 release run's license gate blocked @img/sharp-wasm32@0.35.5
(Apache-2.0 AND LGPL-3.0-or-later AND MIT). sharp sat in graph-ui's tree
only because @huggingface/transformers lists it for its Node image path.
CBM Lens runs Transformers in the browser (a tokenizer and a causal LM on
WebGPU), never processes images, and the Transformers web build already
replaces sharp with an empty object. Yet sharp installed 14 LGPL packages
(10 @img/sharp-libvips-*, 3 @img/sharp-win32-*, @img/sharp-wasm32), and
the gate let them through two ways:
- a reviewed exception for exactly @img/sharp-wasm32@0.35.0 ("installed
but not shipped"), which the 0.35.5 bump in #2632 tripped;
- collect() skipped every os/cpu-restricted package as "build tooling",
which hid all ten LGPL libvips binaries.
A non-permissive license has no place in the tree, shipped or not:
- sharp now resolves to graph-ui/stubs/sharp, our own MIT stand-in that
throws if anything ever calls it (direct dependency file:./stubs/sharp
plus override "sharp": "$sharp"). The whole sharp family leaves the
lockfile: 441 -> 411 packages, zero LGPL/GPL left (audited).
- ui_browser_licenses.py loses the exception and keeps only the browser
build evidence check; license-gate-check-npm.py validates that evidence
unconditionally, checks platform-restricted packages like any other,
and has no exclusion path; gen-ui-licenses.py drops the exception
section.
- tests: the exception tests become guards: an unshipped LGPL package
blocks, a platform-restricted LGPL package blocks, a platform-restricted
MIT package passes. Against the old scripts both LGPL guards fail.
The shipped browser bundle is unchanged: rebuilt, it differs from main's
only by the build's own -dirty version marker. License gate stage 3 on
this tree: 211 production packages, all allow-listed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
All 17 open alerts sit in graph-ui/package-lock.json. Fixed versions:
- sharp 0.35.0 -> 0.35.5 (GHSA-wq5f-xc86-pv6w, GHSA-rgj7-g3m4-5g8c):
the existing @huggingface/transformers override, bumped.
- adm-zip 0.6.0 -> 0.6.1 (GHSA-p634-w6r4-rjp2, GHSA-c6fg-446q-cg94,
GHSA-8238-w5pm-2374, GHSA-rcw4-f5rp-g42v, GHSA-j5f4-cc29-5x44,
GHSA-7q85-xj36-vmfc, GHSA-vwc7-r8mq-g2x9 whose range ends at 0.6.0):
the existing onnxruntime-node override, bumped.
- dompurify 3.4.8 -> 3.4.16 (GHSA-6688-9rhm-gjv2, GHSA-55q2-fjhq-7xh7,
GHSA-c2j3-45gr-mqc4, GHSA-cmwh-pvxp-8882, GHSA-vxr8-fq34-vvx9):
monaco-editor pins it exactly, so a scoped override.
- yaml 2.8.2 -> 2.8.3 (GHSA-48c2-rrv3-qjmp): the direct pin.
- source-map-js 1.2.1 -> 1.2.2 (GHSA-68fv-2mgg-jv7q): in range under postcss.
- sprintf-js <= 1.1.3 (GHSA-hp3w-g68c-fv3c) has no fixed release. Its only
path is onnxruntime-node -> global-agent 3 -> roarr 2. global-agent
4.1.3 drops roarr and keeps the CommonJS `bootstrap` export that
onnxruntime-node's postinstall calls, so it is overridden under
onnxruntime-node and sprintf-js leaves the tree.
Lockfile delta: no package added; 7 removed (global-agent 3's private
dependencies: boolean, detect-node, es6-error, json-stringify-safe, roarr,
semver-compare, sprintf-js); 35 re-versioned (sharp's @img platform
packages, the five above, global-agent 4's matcher/serialize-error/
type-fest). Everything resolves from registry.npmjs.org.
Proof: `npm ci` with install scripts on, as the product build runs it;
onnxruntime-node's postinstall run directly under global-agent 4.1.3
exits 0; the production `vite build` passes; scripts/ci/test-ui.sh
(vitest, style gate, promise scan, portable acceptance checks,
production build) and scripts/license-gate.sh pass.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Rename the reading workspace to CBM Lens Beta, distinguish Beta with an amber badge, and keep build diagnostics out of the header. Put architecture history beside the active context and record meaningful exploration steps.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Preserve unfinished model operations across repeated project switches, retain truncated graph metadata for file and folder scopes, and give each browser hand test a fresh profile directory without deleting existing data.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Since the branch node reads "cbm · working tree", a search for "working"
ranked it behind the folders of the other hits and cut it from the list.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The answer about the current view listed the branch node by its bare
"DETACHED", and the card of a folder said "Selected: .github (Folder) in
.github". Both now use the names the Galaxy shows.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The server writes next_offset and truncation_reason under a full page,
candidate_window_saturated for very many candidates, and the lines of a
too small output budget. The search parser knew none of them, so every
search with more than one page fell back to "Index search unavailable".
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
N1: The index puts a Branch node above the top level folders and files,
named after the branch, "DETACHED" for a detached HEAD and "working-tree"
where no branch is known. Galaxy showed that bare name, and in the
hierarchy of .github it read like a folder. One helper
(galaxy/node-names.ts) now names it from the label Branch or the qualified
name pattern <project>.__branch__.<slug>: "django-demo · detached HEAD",
"cbm · working tree", "django-demo · branch main". Galaxy labels in both
views, root markers, the hover card, the search, the toolbar root, history,
Path to, Selection details and the chat evidence, topic and listed answers
use it; German answers read "losgelöster HEAD", "Arbeitsverzeichnis" and
"Branch-Knoten". Tooltips and the hover card keep the name in the index.
The "{}" the index stores as the file of a Branch node is no file any more
(no file "{}" in the search, no open source button), the scoped hierarchy
frames the wider name instead of cutting it at the left edge, and line 0 is
no line range in the hover card. Scopes, history keys and the chat snapshot
keep the names of the index, so typed names match as before.
N2: The note "nothing of this walk is in focus: the ring follows the symbol
in front of the reader" stood under the scoped hierarchy in the Galaxy tab,
where the root stands in the middle and Explore is not open. It now shows
only beside Explore's reader, when no node of the walk is open there, and
says "None of these nodes is open in Explore; the ring marks the symbol
open there." Both hierarchy strings moved to galaxy-strings.ts in plain
words.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
With .github selected in the Galaxy hierarchy, "kkannst du mir die heirarchie
erklären" and "erkläre die aktuelle hierarchy" went to the free model, which
answered "Ich kann dir die Heirarchy erklären." and "Die aktuelle Hierarchie
erklärt.".
Questions about the current view (die Hierarchie, die Ansicht, den Graphen,
den Ausschnitt, die Struktur, this view, the hierarchy, what am I looking at,
was sehe ich hier), typos included, now get a listed answer from the loaded
scope in the language of the question: the root with its kind in the middle,
incoming and outgoing relationships by type with count and bounded names, how
far the scope reaches and how the picture is read. The Galaxy evidence carries
which picture is shown; switching it keeps the content identity, so the
automatic explanation is not written again.
A free model answer that only restates its question is no longer shown as an
answer: the turn says the model gave no answer, lists the facts of the
selection and offers Ask again, which tells the model not to restate the
question. A restating sentence under the facts of a general question is left
out. Short real answers such as "Ja, 11." stay.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
Both chat branches touched the same places. The grounded answer keeps the
lines read from the code and takes the reason of a dropped sentence; the
divider says "Back to" for a returning topic and "New topic" in the
language of the turn otherwise; examples follow the kind of the selection
and the hint offers no model. The new tests of the behaviour branch now
expect the reworded texts, and the German follow up answer quotes the
prompt like the other German hints.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The outline of django's pyproject.toml showed "dependencies [; authors [".
An array or inline table that runs over several lines is now read to its
end, and its items are split at its own commas only, so an inline table
such as an author stays one item.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
After a few answers built from facts, "Explain the marked code line by
line" got the first fact line back from the model ("Marked lines 50-54 of
general.py"). The history of a later request now carries a grounded answer
as its model sentence (its facts only when the sentence was left out), a
file outline as its heading and purpose and a listed answer as its list.
The code lines and the note on who wrote what stay out: the request carries
the source anyway, and a model answer must not say "not generated by the
model".
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The lines read from JSONBAgg ended mid-template at the panel edge, behind
the scrollbar macOS hides. Code blocks in chat answers now wrap long lines,
as the Source block does since K15.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The hand test asked for every Refresh button to say what it did; only the
four in Architecture did. Measured in the browser, three more showed
nothing that lasted: Refresh in ADR changed nothing for a single frame,
Refresh projects in the project picker showed "Loading projects..." for
about 150 ms and then the same list, and Refresh in the file impact of
Explore folded the details into "Reading dependencies…" for two seconds
and brought back the same numbers.
The control and its hook move from architecture/ to ui/refresh/, with the
shared words "Up to date at …: no changes since the last load" and
"Refresh failed at …", and these three buttons use it: they read
"Refreshing…" while they run and then name the time and whether anything
changed. Where the view already shows an error in its own words, the
status names only the time. The file impact keeps its details on screen
while a refresh of the same file runs. In the project picker the status
stands on its own line under the buttons.
The System buttons already show it ("Updated" and "Read" with the time),
and the Refresh buttons of Settings, of the projects panel and of the
daemon alerts are not mounted anywhere in the app, so they stay as they
are.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The line of the service map that got the shared Refresh control (A3) still
had "Fit map" written into the TSX, and so had the repository map. The
label now lives in architecture/strings.ts and both maps read it there.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
With a filter the Start field kept the current start under "Matching
operations · N of M" even when it did not match, so the group held one
entry more than its count: "5 of 61" with six entries, the last one
"main · …/manage.py-tpl". It also stood among the suggestions.
A current start that the filter does not match now has a group of its own,
"Current start, not matching the filter", at the top of the list. The
suggestions and the matches hold only matches, so each count equals its
entries. A current start that matches stays in its place.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
Back, Forward and the subtabs share one row since A1, but the row jumped
when switching between Overview, Routes and Hotspots and the two system
views: System structure and Behavior set the view's frame to 16 px instead
of 28 and 32 and gave the tabs their own padding and gap. "← Back" stood at
x 32, y 98 in the first three and at x 16, y 86 in the other two.
The system views now use the frame and the row of the other subtabs. The
Back button stands at x 32, y 98.3 in all five.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
"was macht diese datei?" about an open Python file in Explore, or "explain
this" about marked code, still got the free model answer, while the same
question about a Galaxy selection got listed facts and one checked
sentence. These questions now get that shape too, in the language of the
question: the file with its kind and length, a module's docstring and its
top level definitions, or the marked lines; for one marked class or
function also the lines of its code. The model adds at most two sentences,
checked like those of the explanation card, and the note says what was
read from the file and what the model wrote.
Questions that ask for detail or anything else still go to the model as
before. Architecture selections keep their English facts. Tests that used
"Explain" only as some question to the model now ask a specific one.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
While a layer loads, Expand +1 is blocked (aria-disabled) and still takes
the pointer and the focus, but it showed no tooltip: there was no text for
that state, and an empty hint shows nothing.
It now reads "Layer 3 is loading; "−" cancels it." on hover and on focus.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The card showed "2310 files · 15299 indexed nodes" beside "2,163 measured
files of 2,310". The view's own detail now gets the same grouping as the
rest of the card, while line numbers after a path stay as they are. Files
by language are listed largest first with Unknown last. The note that
opened every Source block, "Static graph relationships do not establish
runtime execution or repository purpose.", now says plainly that the
relationships come from reading the code and do not show what runs at
runtime, in German under a German answer.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
When a path label found no free spot along its edge, it was drawn where it
covered the least, and that could still be the hierarchy band title (a wide
title across a steep edge): both texts were unreadable. The hierarchy edge
labels already leave out a label in that case.
Path labels now do the same. The edge type stays in the step list, and the
label comes back as soon as the camera gives it a free spot. A later label
keeps clear of the earlier ones as before.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
A short general question about JSONBAgg ("was macht diese klasse? sehr
kurze antwort") got four lines of counts: the model's sentence claimed
"Arrays" and was dropped every time, so the answer never said what the
class is. The answer and the automatic card now list the lines read from
the selected symbol's source under "In the source:" ("Im Quelltext:"),
between the graph facts and the checked sentence.
For a Python class that is its definition with its bases, its class level
assignments and then its methods with their decorators. For a function it
is the signature, joined where it runs over several lines, the first line
of its docstring and, when the body has at most four lines, the body. At
most six lines; the rest is counted ("+3 more attributes and methods").
Other languages get their definition line. Without source nothing changes.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
"Frage zum Beispiel:" now reads "Du kannst zum Beispiel fragen:", and the
uncertain answers offer a choice instead of an order ("Du kannst dir die
Liste ... anzeigen lassen oder das Modell fragen.", "You can show the
list ... or ask the model."). A misspelled name is compared with the
selection by name: "JSONBAg entspricht nicht dem Namen der Auswahl
(JSONBAgg)". The definer uses article and pronoun of each kind ("die
Schnittstelle, die", "der Ordner, der") and the English plural is right
("the classes"). Examples for a prompt without a question fit the kind:
a class gets what it is, who uses it and, when it has INHERITS edges,
what it inherits from; a file or folder gets what it contains. The K16
hand test expects the new name sentence.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The stacking context that keeps the scene labels below the Galaxy panels
(K29) took the hover card of a node with it: next to Selection details the
card was cut off by the panel. A hover card is only there while the pointer
rests on a node, and then it is what the reader wants to read.
The scene now keeps a second layer beside the canvas wrapper, as large as
the scene, and the node card and the coverage card draw into it. drei still
places them with the scene camera, so they stand where they stood before.
The layer lies above every Galaxy panel and below the toolbar menus and the
tooltips, so an open menu stays readable.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
German answers showed "(Method, ...)" and "Ausgewählt: JSONBAgg (Class)".
Kinds are now written in the language of the answer (Methode, Klasse,
Datei, Funktion, Modul, Schnittstelle and the other kinds of the index),
while the prompt stays English. The topic divider follows the language of
the turn it heads, with a German text beside the English one. When a side
or a layer is missing, the answer names the controls as Galaxy labels
them: "Incoming", "Outgoing", "Both directions" and "Expand +1". The K17
hand test expects the German divider above its German question.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
"was macht diese datei?" on tox.ini, setup.cfg, .flake8, .editorconfig,
pytest.ini or .coveragerc went to the model, which wrote "Testverwendungen"
for tox.ini. These files now get an outline read from them like YAML, JSON
and TOML: each section with its keys and short values, a value continued
on indented lines as its list, bounded with "+N more". The automatic card
counts sections with the same reader, and .flake8, .coveragerc and
.pylintrc now count as INI files there too.
The outline also says what a well-known file is for, in one line after its
heading, when the name and the structure fit: pre-commit, GitHub workflows,
package.json, pyproject.toml, tox.ini, setup.cfg, Docker Compose, Read the
Docs, EditorConfig, tsconfig, flake8, pytest and coverage.py. Other files
get no such line. The heading no longer says "Read from the file:"; the
note at the end still does.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The note cut the list at six names without saying how many were left
out, and flagged things that are no names, such as %(), %s or False. It
now skips tokens without letters, Python and JavaScript literals and
format placeholders, counts the rest as "+N more", and with eight or more
unknown names says plainly that the answer is likely made up. A word of
letters that only extends a folder name of six letters or more in the
given paths by up to three letters (PostgreSQL beside
django/contrib/postgres) counts as known.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
Every model stops at 512 output tokens, so at the maximum the note no
longer offers larger models for a longer answer. It says they have the
same limit and suggests asking about one part or asking for the rest.
Below the maximum the list stays, without promising longer answers and
without the awkward memory sentence. Under an automatic explanation, which
writes at most 128 tokens, the raise hint and its button appear only when
the reader's limit is below 128, and that limit is called theirs instead
of a choice to keep explanations short.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
Since K29 the scene labels lie below the Galaxy overlays, but the overlays
let a little of the scene through: Selection details at .95, the path panel
at .94, the hierarchy key and the loading pill at .9, the menus at .98, fit
view at 82 %, the agents instrument at 88 and 92 %. The path target's name
and its ring still showed through Selection details.
Every overlay over the scene now keeps its colour without transparency.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The note said the sentence "named something the evidence does not show"
also when it was dropped for a claim word such as "output" or "Array"
that the source does not show. explanationSentence now returns the reason
with the drop, the claim word or the unknown name as the sentence wrote
it, and the notes say what was claimed or named and what it was checked
against, in English and German. The K12 hand test accepts the named form.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
Coming back to a file or selection that already had turns showed "New
topic: <same file>. Earlier messages are not sent with these questions."
and sent none of them, so "Und was noch?" got "Ja, und noch." The divider
now reads "Back to: X. Earlier messages about it are sent again." (German
"Zurück zu: X. ..." for a German question), and the request carries the
earlier turns of that topic again. Turns of other topics still stay out.
A short follow-up right after a change of topic ("und", "mehr", "und was
noch?", "and?", "more") has no turn of its topic to follow. It is now
answered without the model: earlier messages were about another topic and
are not sent, please ask the full question, with the example questions of
a prompt that asks nothing.
The chat check for K17 now expects the return to send the file's own
earlier question and to say "Zurück zu".
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
"Callers of JSONBAgg ... 23 incoming relationships from 12 symbols" was
followed by 11 callers. The heading now counts what it lists, "11 callers
(CALLS) of JSONBAgg in the loaded graph.", and gives all incoming
relationships apart ("All incoming: 23 relationships from 12 symbols.").
What a selection calls is a full sentence in both languages, the German
list of other types is headed "Andere", and a side that cannot be listed
says why in a full sentence. The K16 hand test expects the new heading.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
Every word of the open file counted as a name the prompt could ask about,
so "test" went to the model whenever the file contained the word, and the
model echoed it. Greetings and probe words (test, hallo, hi, ok, ja, danke
and the like) now never count as names unless one of them is exactly the
selection's own name.
The hint for such a prompt no longer offers "Ask the model": the model had
nothing to answer there.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
"Incoming relationships: 23 from 12 symbols" and "2 zu 2 Symbolen" read
like a score. The summary lines now say "Incoming: 23 relationships from
12 symbols" and "Eingehend: 23 Beziehungen von 12 Symbolen", and the empty,
not loaded and cut sides use the same labels. The prompt and the Source
block head each edge type as "CALLS (11):" instead of "CALLS from 11:",
which the model repeated as a sentence. The K7 hand test and the call
feedback acceptance check expect the new wording.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
"Ask the model" under a listed, grounded or file answer put the model's
text in place of that turn, so the 11 listed callers became one sentence
naming one of them. The model's reply is now a turn of its own below the
listed one, with the same question and the line "Asked the local model".
Every answer the model wrote freely now says so under it, in the language
of the question ("Generated by the local model; it can be wrong."), also on
an explanation card without listed facts. The button under such an answer
reads "Ask again" instead of "Retry"; after an error it stays "Retry".
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
"complete for the indexed graph" read as if the whole graph was loaded,
while it only means the traced scope finished loading. The scope sentence
now says "fully loaded" and "vollständig geladen".
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The scope sentence said "5,548 symbols ... stopped at the render limit of
5,000 nodes", which contradicts its own numbers and mixes two units. It now
says what the Galaxy tooltip says: loading stopped after the request that
took the layer past the limit, and the scene draws at most that many nodes.
The limit gets its own sentence, so symbols and nodes never share one.
Card, prompt and listed answers, in English and German.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The new German sentence said "noch nicht", which the promise scan reads as
a promise; both languages now state the condition.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
The project switcher turned "?project=django-demo&workspace=galaxy" into
"?project=cbm", so a reload could open another workspace. The new
address now keeps the page-wide parameters App names (the workspace and
the walk bounds) and nothing of the old project, and the address always
names the workspace in view, also one carried over a switch or chosen
from storage. Browser Back and Forward between projects work as before.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>