Dependabot Cleanup + Tanuj-Intent Port — Removed 3 Unused Deps, Forced 4 Transitive CVE Patches, Ported Explicit Save Flow
Two-commit cleanup that eliminates the bulk of the 28 open Dependabot alerts on this repo and absorbs the intent of TanujKS's August 2025 work (which we force-pushed past in 2026-05-01_02 — his commits are archived on the auto-rescued `feature/save-all-citations` branch). First commit removes fastify, @modelcontextprotocol/sdk, and zod (zero imports across src/ and main.ts since they were added in 644582d) and forces patch/minor bumps on four surviving dev-tool transitive CVEs via pnpm.overrides. Second commit ports the explicit save flow — `autoSaveUrlCitations` setting (default off), 'Save All Hex Citations' command, modal-level 'Save All Hex (N)' button, per-citation 'Save to Citations' button — without any of his `any` types. Build clean throughout.
Why Care?
Two thematically separate but practically coupled cleanups landed in
quick succession on development after the force-push that overwrote
TanujKS's three Aug-2025 commits:
Dependabot was screaming at us — 28 open alerts, dominated by transitive CVEs from three direct dependencies (
fastify,@modelcontextprotocol/sdk,zod) that had been carried inpackage.jsonsince commit644582dbut never imported by any plugin code.grepacrosssrc/andmain.tsreturned zero matches for all three. They were paying the security-alert tax without delivering any feature.Tanuj's intent was on the day's task list — making
Citations/a curated archive rather than a side-effect of every URL extract. The user's broader "evaluate how to use bases for canonical source citations" framing wants explicit curation ("some, not all"). Tanuj's commits already implemented this; the force-push removed them fromdevelopment; this changelog records absorbing the same intent into our refactored, type-safe code.
The two changes ship together because they touch related plumbing
(package.json edits + a settings-driven flow change to citation
file creation) and dropping the unused deps cleared the conceptual
deck for thinking about what citations should be saved when.
What Was Built
Commit ad88cd9 — chore(deps): remove unused fastify/MCP/zod; pnpm overrides for transitive CVEs
Removed direct deps (zero imports — confirmed by grep across src/
and main.ts):
| Package | Direct alert(s) | GHSA IDs |
fastify | 4 | GHSA-247c-9743-5963, GHSA-jx2c-rxcm-jvmq, GHSA-444r-cwp2-x5xf, GHSA-mrq3-vjjr-p77c |
@modelcontextprotocol/sdk | 3 | GHSA-345p-7cg4-v4c7, GHSA-8r9q-7v3j-jr4g, GHSA-w48q-cv73-mx4w |
zod | 0 (current) | — flagged for removal in 2026-05-01_01.md already |
Removing fastify also dropped these transitively-vulnerable
packages entirely from the dependency graph:
path-to-regexp, body-parser, qs — three more alerts gone for
free, with no further action.
Lockfile size: 74k → 43k (~40% smaller).
pnpm.overrides added to force safe versions of four surviving
transitive packages whose vulnerable versions remained pinned via
older eslint/typescript chains:
"pnpm": {
"overrides": {
"ajv@<6.14.0": "^6.14.0",
"js-yaml@<4.1.1": "^4.1.1",
"minimatch@<3.1.4": "^3.1.4",
"flatted@<3.4.2": "^3.4.2"
}
} | Package | Before override | After override | Closes alert |
| ajv | 6.12.6 | 6.15.0 | GHSA-2g4f-4pwh-qvx6 |
| js-yaml | 4.1.0 | 4.1.1 | GHSA-mh29-5h37-fv8m |
| minimatch | 3.1.2, 10.2.5 | 3.1.5, 10.2.5 | GHSA-7r86-cg39-jmmj, GHSA-23c5-xmqv-rm74, GHSA-3ppc-4f35-3m26 |
| flatted | 3.3.3 | 3.4.2 | GHSA-25h7-pfq9-p65f, GHSA-rf6f-7fwh-wjgh |
These four are dev-tool transitives — they only execute at lint/build time and are never bundled into the runtime plugin by esbuild — so the practical risk was always near-zero. The override existence is mostly about silencing Dependabot rather than closing real exposure.
.npmrc got ignore-workspace=true added. The cite-wide repo
sits inside /Users/mpstaton/code/lossless-monorepo/, whose
pnpm-workspace.yaml lists site and content as workspace
members. pnpm 10 was nonetheless treating cite-wide as a workspace
member when invoked from within it, which kept blocking installs on a
"will remove parent monorepo's node_modules — proceed?" prompt.
The .npmrc setting alone wasn't enough — pnpm 10 only respects
workspace-isolation as a CLI flag (--ignore-workspace) for some
operations. The working invocation became:
pnpm install --ignore-workspace --no-frozen-lockfile The .npmrc entry stays as documentation and a forward-compat hook
in case pnpm later reads it from config consistently.
Commit c3c8717 — feat(citations): explicit save flow + autoSaveUrlCitations setting
The intent, in one sentence: Citations/ is a curated canonical
archive, not a side-effect of every URL extract.
Three save paths now exist, in order of "least to most user effort":
Settings-toggle auto-save —
Settings → Cite Wide → Auto-save URL Citations. Off by default (matches the user's "some, not all sources should be canonicalized" framing). When on, the URL extract still triggerscreateCitationFileas before. When off, the URL extract only updates the document; the user explicitly canonicalizes later.Bulk command — palette command "Save All Hex Citations to Citation Files" walks the active document, finds every
[^hexId]group, and persists each as a citation file. Reportssaved / updated / errorscounts in a single Notice.Per-citation in modal — open the Citations modal (existing
Show Citations in Current Filecommand); each hex group now has a "Save to Citations" button (in place of the no-op "Convert to Hex" that previously rendered for hex groups), and the modal header shows "Save All Hex (N)" alongside the existing "Convert All (N)" — each conditional on the matching count being greater than zero.
Type-safety improvements over Tanuj's original:
His
saveHexCitationFromGroup(group: any, ...)→ ourssaveHexCitationGroup(group: CitationGroup, ...).His
group.matches.find((match: any) => ...)→ ours typed asCitationMatch.His
await import('./citationService')(workaround for an imagined circular dep) → ours uses a staticimport { citationService }. Confirmed by inspection:citationService.tshas zero imports, so there's no cycle to dodge.
API additions to citationFileService:
export interface SaveAllHexResult {
saved: number;
updated: number;
errors: number;
}
class CitationFileService {
public async saveAllHexCitationsFromContent(
content: string,
sourceFile?: string
): Promise<SaveAllHexResult>;
public async saveHexCitationGroup(
group: CitationGroup,
sourceFile: string | undefined
): Promise<'saved' | 'updated' | 'error'>;
} The per-group method is public so the modal can call it directly
without rebuilding a content slice — cleaner than Tanuj's draft, which
had a parallel saveHexCitationToFile in the modal class duplicating
the service logic.
Skipped from Tanuj's commits: the visual polish (citation-id
badge, inline citation-text preview panel inside expanded groups,
hover transforms, citation-text section, separator). Best handled as
a separate styles pass when we next touch styles.css — keeps this
commit's scope tight to the behavioral change.
Verification
Build clean across both commits:
tsc -noEmit -skipLibCheck && eslint . && esbuild production. Type-
safety pass from 2026-05-01_02 is preserved — no any introduced.
What Changed in Approach (the meta-lesson)
| Pattern this rejects | Pattern this adopts |
| Carry unused dependencies "in case we need them later" | Audit imports periodically; remove deps with zero references — they're paying security tax for no feature |
| Treat Dependabot alerts as a single yes/no — fix all or ignore all | Triage by exposure: direct vs transitive, runtime vs build-time. Force versions on the latter via pnpm overrides; don't block on theoretical lint-tool ReDoS |
| Auto-create canonical artifacts on every related event | Default to no auto-creation; require an explicit gesture (button, command, setting toggle) so the user's curation intent is preserved |
Trust the previous author's await import() as evidence of a real circular dep | Verify the dependency graph yourself before replicating workarounds |
| Pull in three contributors' commits when the contributor's intent is clearer than their implementation | Force-push past, archive their work on a rescue branch (auto-created here as feature/save-all-citations), and re-implement the intent fresh in the cleaner codebase |
The generalizable point: dependency hygiene and feature curation are the same kind of move — both push back on default "yes" behavior that accumulates surface area without paying for it. The unused deps were paying for nothing. The auto-save default was creating archive files the user didn't want yet. Both got the same treatment — opt out by default, opt in by explicit gesture.
Open Items
Push to remote. Both commits are local on
developmentonly; Dependabot won't see the lockfile changes (and won't close the alerts) until the branch is pushed. Deferred per the established session pattern (no shared-state mutation without explicit user confirmation). User push when ready:git push origin development(regular non-force — fast-forward only since the force-push in2026-05-01_02already aligned local with remote at688bb55).Visual polish from Tanuj's commit
8a9f3c6— citation-id badge, inline citation preview panel, hover transforms, separator. Available verbatim incontext-v/workflow/2026-05-01_Refactor.mdand on the rescuedorigin/feature/save-all-citationsbranch. Pick up in a separate styles commit.Orphan citation files from dedup. Carried over from
2026-05-01_03.mdopen items: whendedupe-citations-by-urlcollapses[^def456]→[^abc123], theCitations/def456.mdfile remains on disk. A "Garbage Collect Orphan Citation Files" command would handle this; still unscheduled.Inheriting usage stats during dedup. Same as above — canonical's
usageCount/filesUsedInaren't merged from eliminated hexes. Right time to do this is during the dedup apply phase, before deleting the duplicate reference line.feature/save-all-citationsbranch on remote. Auto-rescued by GitHub when the force-push in2026-05-01_02removed Tanuj's commits fromdevelopment. Now that his intent is absorbed (commitc3c8717), the branch is purely archival. Decision pending: delete after some safety window, or keep as a permanent contributor-attribution record.Bigger "evaluate Bases" thread. This commit only ports the curation gesture; the deeper question of whether citation files should be reshaped to be Obsidian Bases-compatible (or treated as the foundation of a future RAG/KAG context store) is unresolved. Hold for a separate spec session.
Files Touched
cite-wide/
├── package.json (modified — removed 3 deps; added pnpm.overrides)
├── pnpm-lock.yaml (regenerated; 74k → 43k)
├── .npmrc (added ignore-workspace=true)
├── main.ts (modified — gated auto-save; new save-all-hex-citations command)
├── src/
│ ├── settings/
│ │ └── CiteWideSettings.ts (added autoSaveUrlCitations + toggle UI)
│ ├── services/
│ │ └── citationFileService.ts (added SaveAllHexResult,
│ │ saveAllHexCitationsFromContent,
│ │ saveHexCitationGroup)
│ └── modals/
│ └── CitationModal.ts (Save All Hex header button;
│ per-group Save to Citations;
│ conditional Convert All)
└── changelog/ (originally created at context-v/changelogs/; relocated to repo-root changelog/ on 2026-05-17)
└── 2026-05-01_04.md (this file) Reference
Commits in this entry:
ad88cd9,c3c8717ondevelopment.Predecessors that set up the conceptual deck:
2026-05-01_01.md(deps refresh; flagged unused deps for removal),2026-05-01_02.md(type-safety pass; force-pushed past Tanuj's branch),2026-05-01_03.md(dedupe by URL).Tanuj's archived work:
origin/feature/save-all-citations(auto-rescued at force-push), commitsef99b16,37995cd,8a9f3c6. Full source captured for reference incontext-v/workflow/2026-05-01_Refactor.md.Dependabot UI:
https://github.com/lossless-group/cite-wide/security/dependabot— alert closure won't reflect until the lockfile is pushed.