feat(nodes)!: retire 24 nodes the sandbox and Code node already cover - #5348
Merged
Conversation
Remove five clusters whose capability ships elsewhere, and add the snippets that stand in for two of them. - lib.svg element builders (12): an svg_element is a plain object, so a Code node builds the whole list in one place where array order is paint order. Document and SVGToImage stay — the guest has no sharp. - lib.nlp (7): 501 lines of node class over 2,766 of vendored stemmers, Bayes, TF-IDF, phonetics and a sentiment lexicon. No shipped example used it. - lib.mail (3): search_email / add_label_to_email / archive_email were already a second implementation against the same imapflow client, and Gmail reaches a Code node through @nodetool-ai/sandbox-nodetool/google with the OAuth token held host-side. - lib.secret.GetSecret: getSecret(name) does the same read, bound by the run's declared secretScope. The node read any secret and fell back to process.env[name], which is a way around a guarantee the sandbox enforces. - lib.grid.CombineImageGrid: image.grid is the same sharp call, host-side. SliceImageGrid stays; its placement metadata is what makes reassembly exact. Two of these reverse a decision in CODE_NODE_COVERAGE.md. Both reversals turn on the same thing: that audit asked whether a guest script could do the work, when the replacement was a host capability. New snippets: gmail-search, gmail-add-label, gmail-archive (category Email) and image-grid (category Image). lib.nlp is removed with no replacement. Stemming, TF-IDF, sentiment and phonetic matching have no in-product answer until a sandbox-nlp pack lands; the gap is written down in docs/CODE_NODE_COVERAGE.md rather than implied. The three shipped SVG examples now build their elements in one Code node. The gradient card also references its gradient, which the original defined and never used.
lib-nlp.ts was the only importer of `compromise` (entity extraction), and lib-mail.ts the only importer of `imapflow` in integration-nodes. Nothing in the repo imports either now — `imapflow` stays declared in packages/agents, which still uses it for the email capabilities. Lockfile drops compromise and its transitive tree (efrt, grad-school, suffix-thumb); no package is added.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Retires 24 node classes across five clusters whose capability already ships somewhere else, and adds the four snippets that stand in for two of them. The registry goes 483 → 459 nodes, net −20,237 lines.
lib.svg's 12 element builders go because ansvg_elementis a plain object and the 12svg-*snippets already shipped;DocumentandSVGToImagestay, since the guest has nosharp.lib.nlp(7) goes with its 2,766 lines of vendored stemmers, naive Bayes, TF-IDF, phonetics and sentiment lexicon.lib.mail(3) goes becausesearch_email/add_label_to_email/archive_emailwere already a second implementation against the sameimapflowclient.lib.secret.GetSecretgoes becausegetSecret(name)does the same read bound by the run's declaredsecretScope, while the node read any secret and fell back toprocess.env[name].lib.grid.CombineImageGridgoes becauseimage.gridis the same sharp call host-side —SliceImageGridstays, and its placement metadata is what makes reassembly exact.Two of these reverse a decision recorded in
docs/CODE_NODE_COVERAGE.md, and both reversals turn on the same thing: that audit asked whether a guest script could do the work, when the replacement was a host capability. It never weighedpackages/agents/src/capabilities/email.tsorimage.grid, neither of which it mentions.lib.nlpis removed with no replacement, deliberately. Stemming, TF-IDF, sentiment and phonetic matching have no in-product answer until a@nodetool-ai/sandbox-nlppack lands. That gap is written intodocs/CODE_NODE_COVERAGE.mdas follow-up work rather than left implied. No shipped example used any of the removed nodes.The three shipped SVG examples now build their element list in one Code node, where array order is paint order — two Code nodes feeding a List collect in arrival order, which is not deterministic. The gradient card also now references its gradient; the original defined one and never used it.
Verification
Run on this diff (a missing
mesa-vulkan-driversICD was installed per AGENTS.md § WebGPU on a headless machine, andpackages/model3dneeded its missing workspace symlink):npm run test:affected— the sandbox packs are not workspaces, so selection falls back to everything. Ran the whole pass instead: packages 112/113 tasks, web 1201 suites / 13,694 tests, electron 63 suites / 686 tests, all green.npm run typecheck— web and electron clean.npm run lint— exit 0. It caught an orphanedGradientLibNodeOutputstype alias left by the SVG trim, now removed.npm run dev:nodetool -- harness gate— 5/5 selfchecks passed (the diff selectsworkflow-authoring,workflow-execution,dsl-native-flow,sandbox-packages,web-editor).npm run validate:examples— 255/255 graphs validate cleanly.Two pre-existing failures are unrelated to this diff and reproduce identically on a clean tree:
@nodetool-ai/protocol#test— 2 suites fail to load onCannot find package 'ajv/dist/2020.js'; ajv 6.15.0 is hoisted at root whilepackages/protocoldeclares^8.20.0. All 974 of its tests pass. Confirmed bygit stash+ re-run.mobiletypecheck —mobile/node_modulesis absent (mobile is intentionally not a root workspace). Nothing inmobile/is touched by this diff.Checks inverted to prove they can fail
The validator was inverted once by pointing a rewritten example back at a retired type:
The snippet analyzer I used to check the four new bodies was also inverted — and the first version of it was wrong: it tested
"message" in parsedwhen the error key iserror, so it reportedconst x = ;as parsing fine. Corrected, with controls that discriminate:The
docs/nodes/catalog.jsonedit was checked semantically rather than by diff size — git presented 160 insertions that were pure alignment noise: 24 types removed, 0 added, 0 surviving entries modified, no metadata drift.Agent capabilities
No capability is added, and no capability's declared contract changes. The four new entries are editor snippets in
web/src/config/codeSnippets.ts, which are virtual nodes, not capabilities — they callgmail_search/gmail_modify_labels, which already exist with unchanged schemas.New checks
No check, rule, or audit is added. Two existing ones were repointed off retired nodes rather than weakened:
packages/image-nodes/tests/lib-grid.test.tskeeps the assertion that slice placements tile the canvas exactly with no gaps or overlaps — the property that makes reassembly possible — and drops only the two tests that neededCombineImageGrid.packages/base-nodes/tests/e2e/lib-grid.test.tsnow assertsCombineImageGridis absent from the registry, so the retirement itself is pinned.&,<and"throughDocument, exercising the same escape helpers the deleted builders used.Four synthetic test fixtures that used
lib.grid.CombineImageGridas an arbitrary list-input node were repointed tolib.svg.Document, which still exists and has the samelistfan-in shape.Generated by Claude Code