Reconcile main with published npm line (v0.2.86); bump to 0.2.87 - #31
Merged
Conversation
…re + ApiStore)
Introduce src/item-store.ts: a single ItemStore interface with two transports
(LocalItemStore over the on-box JSON store, ApiItemStore over the /v1 HTTP API +
bearer key via @hasna/contracts). A mode resolver picks the transport from the
client-flip env (HASNA_KNOWLEDGE_API_URL + HASNA_KNOWLEDGE_API_KEY and/or
*_STORAGE_MODE); an explicit --store/store_path override pins local.
Route every knowledge-item CLI command and MCP item tool through the Store,
deleting the per-command if(cloud){...}else{local} split-brain branches. self_hosted
and cloud both use the identical ApiItemStore client path.
Pin @hasna/contracts to the fleet-dist tarball so bun install resolves (0.5.x is
not on the public registry). Bump version to 0.2.84.
Build green; full test suite 173/173 pass.
…e registry descriptor truthful The parallel RemoteKnowledgeClient (src/remote-client.ts) was a second HTTP transport using raw fetch, entirely separate from the sanctioned ApiStore (@hasna/contracts client wrapped by src/cloud-store). Its data methods were never invoked by any CLI command, MCP tool, or SDK method and POSTed to /api/v1/knowledge/* endpoints the server never implemented. Removed the class, service.remoteClient(), the SDK remote.client/remote.contract block, the MCP knowledge_storage remote_contract field, and the dead 'remote status/contracts' test coverage. The server-served /v1/registry descriptor advertised the same phantom /api/v1/knowledge/* endpoints. Replaced remote-client.ts with a truthful src/registry-contract.ts that declares only the endpoints src/serve actually routes (/v1/registry, /v1/notes CRUD, /health, /version, /ready, /openapi.json). Every knowledge-item path routes through the ItemStore (Local/Api) and the sqlite catalog stays gated behind assertLocalCatalogMode; no raw fetch or ungated Database open remains on the client. Full suite: 178 pass.
…mmands In self_hosted/cloud (api) mode the shared corpus is the cloud knowledge-items. The corpus retrieval commands (search/ask/build/context) already route over those items; this closes the remaining cloud-mode gaps so no corpus command silently touches local storage or throws the local-catalog guard by surprise: - mcp knowledge_get (getKnowledgeRecord): in api mode restrict `auto` to the cloud-backed `item` kind and refuse an explicit local-catalog kind with a clear message, instead of falling through to sqlite snapshots that throw. - cli ask/build: skip ensureStore() local db.json seeding in api mode. - inventory (cli + mcp): add service.cloudInventory() so `inventory` reports the shared cloud item corpus via the cloud transport instead of reading the local db.json / opening the local sqlite catalog (which refused on flipped fleet machines with a leftover knowledge.db). Extracted itemOnlyInventory() shared by the local no-db path and the cloud path. The local RAG-indexing pipeline (sources/chunks/embeddings/wiki/sync/machines/ reindex) remains local-only behind the single openKnowledgeDb choke-point guard — it has no cloud server counterpart (serve.ts exposes only notes CRUD), so it refuses loudly in cloud mode (never split-brain) rather than routing. Adds tests/cloud-inventory.test.ts. All 180 tests pass; build + tsc clean.
…tore in all 3 modes The SDK exposed no item CRUD and its inventory() called the local-sqlite service.inventory(), so app code could not route items through the unified Store and diverged from the CLI/MCP in api mode. Fix at the source: - KnowledgeService: add itemStore() + item CRUD (list/get/create/update/ delete/deleteMany) routing through resolveItemStore, and resolveInventory() that dispatches to the cloud item corpus in api mode and the local catalog otherwise. - SDK: expose client.items.* and make client.inventory() async via resolveInventory so it never reads a divergent store. - CLI + MCP + project-panel: use the single resolveInventory dispatch instead of per-caller cloud/local branching; project-panel is now async so it no longer hits the local-catalog guard on a flipped box. - index.ts: export the Store contract (ItemStore, KnowledgeItem, resolveItemStore, cloud-store helpers) for SDK consumers. - Rebuild bundles + dist types.
…ent DSN surface
Enforce the ONE-Store standard across the remaining leaks the adversarial
review found:
- SPLIT-BRAIN READ: itemResources() (MCP knowledge://project/items/{id} list)
read the local db.json directly via readStoreLocked/loadStore, with no
api-mode branch — enumerating stale local items in self_hosted/cloud while
every item tool routed to the cloud, and creating a spurious on-box db.json
during the flip. Route it through itemStoreFor(...).listAll() like ok_list;
delete the now-dead readStoreLocked/loadStore/withLock imports.
- DEAD/DUPLICATE TRANSPORT: remove the generated raw-fetch KnowledgeApiClient
(x-api-key) that was exported on the SDK surface but used by nothing (the
ApiStore uses @hasna/contracts). Delete src/generated/knowledge-api-client.ts,
its generator scripts/generate-sdk.mjs, and the generate:sdk build step.
- CLIENT-SURFACE DSN HELPERS: delete getStorageDatabaseUrl / getStorageDatabaseEnv
/ getStorageDatabaseEnvName / STORAGE_DATABASE_ENV / KNOWLEDGE_STORAGE_ENV /
KNOWLEDGE_STORAGE_FALLBACK_ENV / StorageEnv at the source and drop the
DATABASE_URL reporting fields (configured/env/activeEnv) from getStorageStatus.
A raw DB DSN is never a client concept. Update tests + README accordingly.
Build + full test suite (180) green.
…rop dead remote command - context-pack: truncateText reserved maxChars-1 then appended a 3-char ellipsis, yielding maxChars+2. fitPackToBudget's length>N truncation branches could never satisfy their threshold, so the budget while-loop spun forever and 'context pack'/knowledge_context_pack hung in local mode. Reserve the ellipsis width so results never exceed maxChars. - project-panel: hasUriScheme accepted any scheme (generic scheme:) while the contract only allows a fixed list, so cloud knowledge items carrying URLs like s3:// blew up parseContract with a ContractValidationError. Delegate to the contract's UriSchema and guard the notes evidenceRef. - remote: the prior refactor removed service.remoteContract/remoteClient (and the SDK/MCP surface + tests) but left the CLI 'remote contracts| status' handler calling them, so both crashed with 'remoteContract is not a function'. Removed the dead command, help, and completions. - Regression tests for the fit loop and unsupported evidence URI schemes.
… divergence main had diverged from the deployed npm runtime. The published line carried a Store-unification + cloud-routing refactor (6 commits) that never landed on main, while main carried two CLI fixes (#23, #24) the published line lacked. This merge re-converges both histories with a real merge commit so ancestry is preserved (future `git merge-base --is-ancestor` passes) and no commits are lost. Brings in from npm/knowledge/v0.2.86: - refactor(store): unify item CRUD behind one Store (LocalStore + ApiStore) (1506111) - refactor: remove dead raw-fetch RemoteKnowledgeClient, truthful registry (2b6bd21) - fix: close residual cloud-mode routing gaps for catalog commands (2d235a9) - fix: route SDK item CRUD + inventory through the unified Store in all 3 modes (92c3fcc) - fix: close split-brain read + drop dead API client and client DSN surface (5213a51) - fix: stop context-pack hang, repair cloud project-panel, drop dead remote command (8daa0ea) Retains on top of the refactor: - fix(cli): don't leak internal Error stack on usage/validation errors (#23) - fix(cli): make '<sub> --help' print per-command usage (#24) Both #23/#24 regression tests pass on the merged tree. Version bumped to 0.2.87 (> published 0.2.86) with CHANGELOG so npm and main reconverge on publish. Bundled artifacts (bin/, dist/) rebuilt from the merged source.
This was referenced Jul 24, 2026
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.
Why
mainhad diverged from the deployed npm runtime. Fixes based onmainweretargeting stale code the published runtime no longer uses.
e1eed58(build: self-contain @hasna/contracts so self_hosted CLI installs fleet-wide #21 "bundle @hasna/contracts").npm/knowledge/v0.2.86(tagnpm/knowledge/v0.2.86) carried 6 commitsthat never landed on
main(Store unification + cloud-routing refactor):1506111,2b6bd21,2d235a9,92c3fcc,5213a51,8daa0ea.main(v0.2.81) carried 2 commits the published line lacked:36ae510(fix(cli): don't leak internal Error stack on usage/validation errors #23, don't leak Error stack on usage errors) and089bef6(fix(cli): make '<sub> --help' print per-command usage #24,
<sub> --helpper-command usage).What
Merge the published release tag
npm/knowledge/v0.2.86intomain(real mergecommit, not cherry-pick) so:
git merge-base --is-ancestor npm/knowledge/v0.2.86 <this>nowpasses, and
origin/mainremains an ancestor. No commits lost.mainreconverge on the next publish.bin/,dist/) rebuilt from the merged source.Verification (clean local mode, station env vars unset)
origin/mainnpm/knowledge/v0.2.86sync status, 3 machine-sync ledger), reproduced identically on the base — timing/resource
sensitivity under station load, not merge regressions. The merge introduces zero
new failures relative to the published line.
npm/knowledge/v0.2.86are the fix(cli): don't leak internal Error stack on usage/validation errors #23/fix(cli): make '<sub> --help' print per-command usage #24 regression tests, both pass.bun run build(incl.tsc) is clean.bin/knowledge.js:add --helpprints per-commandusage (fix(cli): make '<sub> --help' print per-command usage #24), bare
addprints a plainError: Usage: ...with no stack/bin path (fix(cli): don't leak internal Error stack on usage/validation errors #23),--versionreports0.2.87.npm/knowledge/v0.2.86andorigin/mainare ancestors of the mergecommit; all 8 relevant commits reachable.
Follow-ups (do NOT re-fix against old main first)
After merge + publish of 0.2.87, rebase the open audit PRs (#25/#26/#27 and the search
stack #28-30) onto the reconciled
mainbefore re-review — they would otherwise re-targetcode the published runtime no longer uses.