Skip to content

fix(context): refresh get_docs when packages change on disk - #117

Open
gsdali wants to merge 1 commit into
neuledge:mainfrom
gsdali:fix/refresh-get-docs-on-package-change
Open

fix(context): refresh get_docs when packages change on disk#117
gsdali wants to merge 1 commit into
neuledge:mainfrom
gsdali:fix/refresh-get-docs-on-package-change

Conversation

@gsdali

@gsdali gsdali commented Aug 21, 2026

Copy link
Copy Markdown

context add writes to ~/.context/packages from a separate process, but a running serve reads that directory once at startup. A long-lived stdio server therefore keeps serving the package list it saw when it launched, so get_docs reports a package as missing when it is already installed, and the only way out is to reconnect the client.

I hit this adding a locally-built docs package while a Claude Code session was open: context query saw it instantly, get_docs could not see it at all.

The mechanism already existed

refreshGetDocsTool rebuilds the tool's library enum and calls sendToolListChanged, the MCP notification that tells a client to re-fetch the tool list. It had exactly one caller, the download_package handler, so a package arriving any other way was invisible.

This adds a second trigger, not a second mechanism.

The change

  • watch.ts, a small debounced directory watcher. Debounced because one install is several filesystem events (a temp file, then a rename into place), which would otherwise rebuild the schema three or four times for one logical change. The watcher is unref'd so it never holds the process open by itself, and a callback that throws cannot tear it down.
  • serve watches the data directory, reloads the store, refreshes the tool. Skipped when --libs is set, since that flag pins the session to a fixed library set on purpose and picking up new packages would defeat it.
  • refreshGetDocsTool is now public, because the trigger lives outside the class. That is the only public surface change; happy to bump the changeset to minor if you would rather treat it as one.
  • loadPackages now syncs rather than only adding. It is called repeatedly now, so a package removed from disk has to leave the store too, which the add-only version could not express.

HTTP needed no change. It builds a fresh ContextServer per session over the same store, so a session started after an install already sees it. Only the long-lived stdio server needed the live notification.

Tests

Five, against the watcher directly: a single change fires once, a burst collapses to one call, stopping prevents further calls, a throwing callback does not kill the watcher, and a missing directory is a no-op.

Verified discriminating rather than merely passing: removing the debounce fails three of the five.

The watcher went into its own module partly so it could be tested at all. cli.ts builds a commander program at module scope, so importing it from a test would run the CLI.

About the local test run

pnpm lint and pnpm build are clean. pnpm test reports 40 failures in my environment, identical before and after this change (I ran the baseline on a stash to be sure). They are all better-sqlite3@11.10.0 failing to build against Node v26, so every sqlite-backed test errors on missing bindings:

Error: Could not locate the bindings file. Tried:
 → .../better-sqlite3/build/Release/better_sqlite3.node

My five new tests pass, taking the suite from 181 to 186 passing. I could not verify the sqlite-backed suites locally, so those are worth a look on your CI rather than taking my word for it.

Housekeeping

Followed the CLAUDE.md conventions: searched open and recently closed PRs and /.plans/ first (nothing related), and added a changeset. No plan file to delete, since there was none to claim.

`context add` writes to ~/.context/packages from a separate process, but a
running `serve` reads that directory once at startup. A long-lived stdio server
therefore kept serving the package list it saw when it launched, and `get_docs`
reported a package as missing when it was already installed. The only way out
was to reconnect the client.

The mechanism to avoid that already existed and was wired to a single trigger.
refreshGetDocsTool rebuilds the tool's `library` enum and calls
sendToolListChanged, which is the MCP notification telling a client to re-fetch
the tool list; it was called only from the download_package handler, so packages
that arrived any other way were invisible. This adds a second trigger rather than
a second mechanism.

- watch.ts: a small debounced directory watcher. Debounced because one install is
  several filesystem events (a temp file, then a rename), which would otherwise
  rebuild the schema three or four times. The watcher is unref'd so it never
  keeps the process alive on its own, and a callback that throws cannot tear it
  down.
- serve: watches the data directory, reloads the store and refreshes the tool.
  Skipped when --libs is set, because that flag pins the session to a fixed
  library set on purpose and picking up new packages would defeat it.
- refreshGetDocsTool is now public, since the trigger lives outside the class.
- loadPackages now syncs rather than only adding. It is called repeatedly now,
  so a package removed from disk has to leave the store too, which the
  add-only version could not express.

HTTP transport needed no change: it builds a fresh ContextServer per session
over the same store, so a session started after an install already sees it. Only
the long-lived stdio server needed the live notification.

Tests cover the watcher directly: a single change fires once, a burst collapses
to one call, stopping prevents further calls, a throwing callback does not kill
the watcher, and a missing directory is a no-op. Verified discriminating by
removing the debounce, which fails three of the five.

Local `pnpm test` shows 40 pre-existing failures in this environment, identical
before and after this change: better-sqlite3 11.10.0 does not build against Node
v26, so every sqlite-backed test errors on the missing bindings. The five new
tests pass (181 to 186 passing). pnpm lint and pnpm build are clean.
@changeset-bot

changeset-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f093bce

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@neuledge/context Patch
@neuledge/registry Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

gsdali added a commit to SecondMouseAU/OCCTMCP that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/OCCTSwiftAIS that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/OCCTSwiftInteraction that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/OCCTSwiftIO that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/OCCTSwiftMesh that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/OCCTSwiftScripts that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/OCCTSwiftTools that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/OCCTSwiftViewport that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/simpleOCCTVP that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/SwiftDXF that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/SwiftJWW that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/SwiftMeshHeal that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/SwiftPMX that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

**The per-class OCCT reference manual IS indexed**, as `occt-refman`, 37,008
sections. This copy said it was not, which sent an agent to the bundled headers
or to WebFetch as a first resort rather than a last one. Those routes remain,
scoped to the case that needs them: a class genuinely absent after an OCCT bump,
before the package is rebuilt.

**`context query` is now a lookup step in its own right.** `get_docs` takes its
`library` from an enum fixed when the MCP server connected, and the server
rebuilds that list only for packages arriving through its own download_package
tool. Anything installed by `context add` is therefore invisible to `get_docs`
for the rest of the session while `context query` sees it immediately. The
failure reads as "package missing", which an agent takes at face value and
escalates on, so the policy now says plainly that it means "not in the list I was
handed". Fixed upstream in neuledge/context#117.

Also records that the `ecosystem` package is indexed, so this standard and every
shared policy are themselves queryable, and what a version in the cache means:
a package is pinned to a release and does not follow its repo.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
gsdali added a commit to SecondMouseAU/SwiftX that referenced this pull request Aug 21, 2026
Two corrections, one of which was actively costing time.

The per-class OCCT reference manual IS indexed, as occt-refman, 37,008 sections.
This copy said it was not, which sent an agent to the bundled headers or to
WebFetch as a first resort rather than a last one.

And context query is now a lookup step in its own right: get_docs takes its
library from an enum fixed when the MCP server connected, so anything installed
by context add is invisible to it for the rest of the session while the CLI sees
it immediately. Fixed upstream in neuledge/context#117.

Copied verbatim from SecondMouseAU/ecosystem okf/policies/context-first.md.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant