@remnic/core 9.46.1 → 9.46.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +2 -2
- package/dist/access-admin-ops-surface.js +3 -2
- package/dist/access-authorization-probe.d.ts +2 -2
- package/dist/access-authorization-probe.js +4 -3
- package/dist/access-boundary.d.ts +2 -2
- package/dist/access-boundary.js +3 -2
- package/dist/access-cli.js +16 -16
- package/dist/access-extraction-force-flush.d.ts +2 -2
- package/dist/access-extraction-force-flush.js +3 -2
- package/dist/access-http-lcm-compaction.d.ts +2 -2
- package/dist/access-http-lcm-compaction.js +1 -1
- package/dist/access-http-lifecycle-flush.d.ts +2 -2
- package/dist/access-http-lifecycle-flush.js +2 -2
- package/dist/access-http-offline-stream.d.ts +2 -2
- package/dist/access-http-query.js +3 -2
- package/dist/access-http.d.ts +8 -2
- package/dist/access-http.js +11 -10
- package/dist/access-identity-continuity-surface.d.ts +1 -1
- package/dist/access-identity-continuity-surface.js +3 -2
- package/dist/access-lcm-surface.d.ts +2 -2
- package/dist/access-lcm-surface.js +3 -2
- package/dist/access-mcp.d.ts +2 -2
- package/dist/access-mcp.js +7 -6
- package/dist/access-memory-search-fanout.d.ts +163 -2
- package/dist/access-memory-search-fanout.js +20 -3
- package/dist/access-namespace-preflight.js +3 -2
- package/dist/access-observe-write-surface.d.ts +2 -2
- package/dist/access-observe-write-surface.js +3 -2
- package/dist/access-offline-manifest.d.ts +1 -1
- package/dist/access-operations-batch.js +4 -3
- package/dist/access-operations.d.ts +6 -5
- package/dist/access-operations.js +6 -5
- package/dist/access-recall-concurrency.d.ts +2 -2
- package/dist/access-recall-concurrency.js +3 -2
- package/dist/access-recall-response.d.ts +2 -2
- package/dist/access-recall-response.js +3 -2
- package/dist/access-recall-surface.d.ts +2 -2
- package/dist/access-recall-surface.js +3 -2
- package/dist/access-schema.d.ts +84 -84
- package/dist/{access-service-loJadYd7.d.ts → access-service-DNBYHK33.d.ts} +2 -1
- package/dist/access-service-helpers.d.ts +2 -2
- package/dist/access-service.d.ts +2 -2
- package/dist/access-service.js +3 -2
- package/dist/access-surface-catalog.d.ts +2 -2
- package/dist/access-surface-catalog.js +1 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +2 -2
- package/dist/bootstrap.d.ts +1 -1
- package/dist/{chunk-WHWDBTCJ.js → chunk-74HN5QUH.js} +2 -2
- package/dist/{chunk-2DSUT7DZ.js → chunk-FQU3HTQM.js} +40 -11
- package/dist/chunk-FQU3HTQM.js.map +1 -0
- package/dist/{chunk-5LRDM4R7.js → chunk-G2L5IZV4.js} +7 -7
- package/dist/{chunk-TQZ4DVBC.js → chunk-GZ3R6XOE.js} +5 -2
- package/dist/chunk-GZ3R6XOE.js.map +1 -0
- package/dist/{chunk-5546W5SI.js → chunk-HLKPRWF4.js} +2 -2
- package/dist/chunk-IXEBUYO4.js +201 -0
- package/dist/chunk-IXEBUYO4.js.map +1 -0
- package/dist/{chunk-RCU25Z66.js → chunk-IXH2U2QT.js} +169 -58
- package/dist/chunk-IXH2U2QT.js.map +1 -0
- package/dist/{chunk-HJ3SVHUW.js → chunk-IZQ5TDFT.js} +9 -4
- package/dist/chunk-IZQ5TDFT.js.map +1 -0
- package/dist/{chunk-RVPTS4U5.js → chunk-JCNJIXZN.js} +2 -2
- package/dist/{chunk-5R6S4DJZ.js → chunk-N5XULCU3.js} +2 -2
- package/dist/{chunk-6H744ZBH.js → chunk-QISYTKG4.js} +2 -2
- package/dist/{chunk-AUMWZSE7.js → chunk-RN53QBM4.js} +4 -4
- package/dist/{chunk-M32URQXV.js → chunk-SIP5DBDN.js} +275 -334
- package/dist/chunk-SIP5DBDN.js.map +1 -0
- package/dist/{chunk-44N6ESJ4.js → chunk-TIDEL77O.js} +2 -2
- package/dist/{chunk-XBMJ35IP.js → chunk-VFZS2HAA.js} +4 -3
- package/dist/chunk-VFZS2HAA.js.map +1 -0
- package/dist/{cli-D_RcqXfZ.d.ts → cli-BWXSPxB9.d.ts} +2 -2
- package/dist/cli.d.ts +3 -3
- package/dist/cli.js +15 -15
- package/dist/config.js +2 -2
- package/dist/explicit-capture.d.ts +1 -1
- package/dist/external-wiki-access.d.ts +2 -2
- package/dist/external-wiki-access.js +4 -3
- package/dist/external-wiki-mcp-tools.d.ts +2 -2
- package/dist/index.d.ts +680 -680
- package/dist/index.js +16 -16
- package/dist/mcp-memory-inspector-app.d.ts +2 -2
- package/dist/operator-toolkit.js +3 -3
- package/dist/{orchestrator-LPGegii3.d.ts → orchestrator-CRR-6sVB.d.ts} +6 -0
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +17 -17
- package/dist/resume-bundles.js +3 -3
- package/dist/schemas.d.ts +76 -76
- package/dist/shared-context/manager.d.ts +8 -8
- package/dist/transfer/types.d.ts +66 -66
- package/package.json +2 -2
- package/src/access-http-lcm-compaction.ts +3 -0
- package/src/access-http.test.ts +645 -0
- package/src/access-http.ts +55 -4
- package/src/access-mcp.ts +1 -0
- package/src/access-memory-search-fanout.ts +305 -2
- package/src/access-operations.ts +6 -0
- package/src/access-service-namespace.test.ts +146 -0
- package/src/access-service.ts +39 -40
- package/src/access-surface-catalog.ts +1 -0
- package/src/orchestration/generic-recall-paths.ts +116 -5
- package/dist/chunk-2DSUT7DZ.js.map +0 -1
- package/dist/chunk-7HXCF4RE.js +0 -72
- package/dist/chunk-7HXCF4RE.js.map +0 -1
- package/dist/chunk-HJ3SVHUW.js.map +0 -1
- package/dist/chunk-M32URQXV.js.map +0 -1
- package/dist/chunk-RCU25Z66.js.map +0 -1
- package/dist/chunk-TQZ4DVBC.js.map +0 -1
- package/dist/chunk-XBMJ35IP.js.map +0 -1
- /package/dist/{chunk-WHWDBTCJ.js.map → chunk-74HN5QUH.js.map} +0 -0
- /package/dist/{chunk-5LRDM4R7.js.map → chunk-G2L5IZV4.js.map} +0 -0
- /package/dist/{chunk-5546W5SI.js.map → chunk-HLKPRWF4.js.map} +0 -0
- /package/dist/{chunk-RVPTS4U5.js.map → chunk-JCNJIXZN.js.map} +0 -0
- /package/dist/{chunk-5R6S4DJZ.js.map → chunk-N5XULCU3.js.map} +0 -0
- /package/dist/{chunk-6H744ZBH.js.map → chunk-QISYTKG4.js.map} +0 -0
- /package/dist/{chunk-AUMWZSE7.js.map → chunk-RN53QBM4.js.map} +0 -0
- /package/dist/{chunk-44N6ESJ4.js.map → chunk-TIDEL77O.js.map} +0 -0
package/src/access-service.ts
CHANGED
|
@@ -107,8 +107,9 @@ import {
|
|
|
107
107
|
defaultNamespaceAtFlatRoot,
|
|
108
108
|
mergeMemorySearchDefaultFallback,
|
|
109
109
|
resolveMemorySearchDefaultFallback,
|
|
110
|
-
|
|
110
|
+
memorySearchThroughScope,
|
|
111
111
|
} from "./access-memory-search-fanout.js";
|
|
112
|
+
import { isSearchExcludedPath } from "./orchestration/generic-recall-paths.js";
|
|
112
113
|
import {
|
|
113
114
|
buildQualityScore,
|
|
114
115
|
buildProposedActions,
|
|
@@ -4711,47 +4712,45 @@ export class EngramAccessService {
|
|
|
4711
4712
|
namespace?: string;
|
|
4712
4713
|
maxResults?: number;
|
|
4713
4714
|
collection?: string;
|
|
4715
|
+
mode?: "search" | "hybrid" | "bm25" | "vector";
|
|
4714
4716
|
principal?: string;
|
|
4715
4717
|
}): Promise<{ query: string; results: Array<{ path: string; score: number; snippet: string }>; count: number }> {
|
|
4716
|
-
const {
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
})),
|
|
4753
|
-
count: results.length,
|
|
4754
|
-
};
|
|
4718
|
+
const { qmd, config } = this.orchestrator;
|
|
4719
|
+
return memorySearchThroughScope(
|
|
4720
|
+
{
|
|
4721
|
+
namespacesEnabled: resolveNamespaceCapabilities(config).namespaces,
|
|
4722
|
+
// `0` is preserved, never coerced: a zero limit is a runtime
|
|
4723
|
+
// compatibility guarantee (AGENTS.md guardrail 4), and it means the
|
|
4724
|
+
// same thing here as an explicit `maxResults: 0` from the caller - an
|
|
4725
|
+
// empty result with no backend call. Anything non-numeric falls back
|
|
4726
|
+
// to the documented default.
|
|
4727
|
+
defaultBudget: typeof config.qmdMaxResults === "number" ? config.qmdMaxResults : 10,
|
|
4728
|
+
// Search-specific: artifacts and the other dedicated surfaces stay
|
|
4729
|
+
// out, but ARCHIVED memories remain findable - explicit search is one
|
|
4730
|
+
// of the surfaces the lifecycle reserves them for.
|
|
4731
|
+
isExcluded: (memoryPath) =>
|
|
4732
|
+
isSearchExcludedPath(
|
|
4733
|
+
memoryPath,
|
|
4734
|
+
// The caller's own collection disambiguates a prefix that is also
|
|
4735
|
+
// a memory category name (`collection: "facts"`).
|
|
4736
|
+
{ ...config, requestedCollection: request.collection?.trim() || undefined },
|
|
4737
|
+
"qmd",
|
|
4738
|
+
),
|
|
4739
|
+
authorizeFlatCorpus: (namespace, principal) => {
|
|
4740
|
+
this.resolveReadableNamespace(namespace, principal);
|
|
4741
|
+
},
|
|
4742
|
+
authorizeNamespaces: async (namespace, principal, collection) =>
|
|
4743
|
+
this.resolveMemorySearchNamespacesForCollection(
|
|
4744
|
+
collection,
|
|
4745
|
+
await this.resolveReadableNamespacesForSearch(namespace, principal),
|
|
4746
|
+
namespace?.trim() ? undefined : principal,
|
|
4747
|
+
),
|
|
4748
|
+
searchAcrossNamespaces: (params) => this.orchestrator.searchAcrossNamespaces(params),
|
|
4749
|
+
searchGlobal: (query, maxResults) => qmd.searchGlobal(query, maxResults),
|
|
4750
|
+
search: (query, collection, maxResults) => qmd.search(query, collection, maxResults),
|
|
4751
|
+
},
|
|
4752
|
+
request,
|
|
4753
|
+
);
|
|
4755
4754
|
}
|
|
4756
4755
|
|
|
4757
4756
|
async memoryProfile(namespace?: string, principal?: string): Promise<Record<string, unknown>> {
|
|
@@ -177,6 +177,7 @@ export const HTTP_ROUTES: readonly HttpRouteEntry[] = [
|
|
|
177
177
|
{ method: "GET", pathname: "/engram/v1/adapters", operation: "adapters_status" },
|
|
178
178
|
{ method: "POST", pathname: "/engram/v1/recall", operation: "recall" },
|
|
179
179
|
{ method: "POST", pathname: "/engram/v1/external-wikis/search", operation: "external_wiki_search" },
|
|
180
|
+
{ method: "POST", pathname: "/engram/v1/memories/search", operation: "memory_search" },
|
|
180
181
|
{ method: "POST", pathname: "/engram/v1/coding-context", operation: "set_coding_context" },
|
|
181
182
|
{ method: "POST", pathname: "/engram/v1/capsules/export", operation: "capsule_export" },
|
|
182
183
|
{ method: "POST", pathname: "/engram/v1/capsules/import", operation: "capsule_import" },
|
|
@@ -13,6 +13,12 @@ export interface GenericRecallPathPolicy {
|
|
|
13
13
|
readonly memoryDir?: string;
|
|
14
14
|
readonly qmdCollection?: string;
|
|
15
15
|
readonly qmdColdCollection?: string;
|
|
16
|
+
/**
|
|
17
|
+
* The collection THIS request named, when it named one. A caller may select
|
|
18
|
+
* a custom collection whose name is also a memory category, which the
|
|
19
|
+
* configured names alone cannot disambiguate.
|
|
20
|
+
*/
|
|
21
|
+
readonly requestedCollection?: string;
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
type GenericRecallPathSource = "filesystem" | "qmd";
|
|
@@ -94,17 +100,122 @@ function isExternalWikiQmdPath(
|
|
|
94
100
|
return isExternalWikiCollectionName(collection);
|
|
95
101
|
}
|
|
96
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Paths an EXPLICIT ranked search must not return.
|
|
105
|
+
*
|
|
106
|
+
* Narrower than {@link isGenericRecallExcludedPath} on purpose. Recall
|
|
107
|
+
* injection also drops archived memories because they are cold by definition,
|
|
108
|
+
* but archive is explicitly reserved for "explicit read or search surfaces"
|
|
109
|
+
* (docs/architecture/memory-lifecycle.md) — hiding it from `memory_search`
|
|
110
|
+
* would remove the only way to find it. Everything else stays excluded: those
|
|
111
|
+
* paths flow through their own dedicated surfaces, never a generic search.
|
|
112
|
+
*/
|
|
113
|
+
export function isSearchExcludedPath(
|
|
114
|
+
filePath: string,
|
|
115
|
+
policy: GenericRecallPathPolicy = {},
|
|
116
|
+
source: GenericRecallPathSource = "filesystem",
|
|
117
|
+
): boolean {
|
|
118
|
+
if (isExternalWikiQmdPath(filePath, source)) return true;
|
|
119
|
+
// A QMD transport hands back collection-qualified paths
|
|
120
|
+
// (`qmd://<collection>/activity/<date>.md`, or `<collection>/activity/…`),
|
|
121
|
+
// and the collection is not always one this policy knows: a caller may name
|
|
122
|
+
// a custom one, and global search spans every collection. The activity
|
|
123
|
+
// predicate is ROOT-AWARE — it matches only the top-level
|
|
124
|
+
// `activity/<date>.md` so a nested ordinary memory stays recallable — so an
|
|
125
|
+
// un-stripped prefix reads as a nested path and the digest would be served.
|
|
126
|
+
//
|
|
127
|
+
// Both spellings are therefore tested. Widening is safe in this direction
|
|
128
|
+
// and only here: a leading segment is dropped ONLY to re-test the dedicated
|
|
129
|
+
// surface shapes, never to decide anything else, and a segment that names a
|
|
130
|
+
// memory CATEGORY (`facts/proj/activity/…`) is never treated as a
|
|
131
|
+
// collection, so ordinary nested memories stay searchable.
|
|
132
|
+
for (const candidate of collectionSpellings(filePath, policy, source)) {
|
|
133
|
+
if (
|
|
134
|
+
isArtifactMemoryPath(candidate) ||
|
|
135
|
+
isNamespacedActivityDigestPath(candidate, policy.memoryDir) ||
|
|
136
|
+
isMeetingRecordPath(candidate)
|
|
137
|
+
) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The activity check, applied against the NAMESPACE root a hit came from.
|
|
146
|
+
*
|
|
147
|
+
* `isActivityDigestPath` is root-aware — the digest must sit directly under
|
|
148
|
+
* the root it is given — but a namespaced search rewrites hits to absolute
|
|
149
|
+
* paths beneath `…/namespaces/<ns>/`, and only the global `memoryDir` is
|
|
150
|
+
* available here. Measured against that root, a real digest at
|
|
151
|
+
* `<memoryDir>/namespaces/team/activity/<date>.md` reads as nested and is
|
|
152
|
+
* served. Re-measuring against the namespace's own root closes that.
|
|
153
|
+
*/
|
|
154
|
+
function isNamespacedActivityDigestPath(candidate: string, memoryDir?: string): boolean {
|
|
155
|
+
if (isActivityDigestPath(candidate, memoryDir)) return true;
|
|
156
|
+
if (memoryDir === undefined || memoryDir.length === 0) return false;
|
|
157
|
+
const relative = path.relative(memoryDir, path.resolve(memoryDir, candidate));
|
|
158
|
+
const namespaced = /^namespaces[\\/]([^\\/]+)[\\/](.*)$/.exec(relative);
|
|
159
|
+
if (namespaced === null) return false;
|
|
160
|
+
return isActivityDigestPath(namespaced[2] ?? "", memoryDir);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** A path as given, plus its form with a leading COLLECTION segment removed. */
|
|
164
|
+
function collectionSpellings(
|
|
165
|
+
filePath: string,
|
|
166
|
+
policy: GenericRecallPathPolicy,
|
|
167
|
+
source: GenericRecallPathSource,
|
|
168
|
+
): string[] {
|
|
169
|
+
if (path.isAbsolute(filePath)) return [filePath];
|
|
170
|
+
// A `qmd://<collection>/<path>` URI states its collection UNAMBIGUOUSLY in
|
|
171
|
+
// the authority, so the leading segment of its normalized form is never a
|
|
172
|
+
// memory category — strip it outright rather than guessing.
|
|
173
|
+
if (source === "qmd" && filePath.startsWith("qmd://")) {
|
|
174
|
+
const normalized = path.posix.normalize(normalizeQmdUriPath(filePath, source).replace(/\\/g, "/"));
|
|
175
|
+
const slashIndex = normalized.indexOf("/");
|
|
176
|
+
return slashIndex <= 0 || slashIndex >= normalized.length - 1
|
|
177
|
+
? [normalized]
|
|
178
|
+
: [normalized, normalized.slice(slashIndex + 1)];
|
|
179
|
+
}
|
|
180
|
+
const normalized = path.posix.normalize(
|
|
181
|
+
normalizeQmdUriPath(filePath, source).replace(/\\/g, "/"),
|
|
182
|
+
);
|
|
183
|
+
const stripped = stripQmdCollectionPrefix(filePath, policy, source);
|
|
184
|
+
const spellings = [stripped];
|
|
185
|
+
// If the AUTHORITATIVE strip already fired — the prefix matched a configured
|
|
186
|
+
// collection — stop. Removing a second segment would take a real directory
|
|
187
|
+
// with it: `memories/projects/activity/<date>.md` would become
|
|
188
|
+
// `activity/<date>.md` and an ordinary nested memory would read as a
|
|
189
|
+
// top-level digest, vanishing from search AND recall.
|
|
190
|
+
if (stripped !== normalized) return spellings;
|
|
191
|
+
const slashIndex = stripped.indexOf("/");
|
|
192
|
+
if (slashIndex <= 0 || slashIndex >= stripped.length - 1) return spellings;
|
|
193
|
+
const prefix = stripped.slice(0, slashIndex);
|
|
194
|
+
// The CALLER's own collection is authoritative: a request for
|
|
195
|
+
// `collection: "facts"` means that segment is the collection, whatever it is
|
|
196
|
+
// also the name of. Otherwise a category-shaped prefix stays part of the
|
|
197
|
+
// path, so an ordinary `facts/proj/activity/<date>.md` memory is searchable.
|
|
198
|
+
const requested = policy.requestedCollection;
|
|
199
|
+
if (
|
|
200
|
+
prefix !== requested &&
|
|
201
|
+
(Object.hasOwn(CATEGORY_MEMORY_ROOTS, prefix) || Object.hasOwn(RESERVED_ARCHIVE_ROOTS, prefix))
|
|
202
|
+
) {
|
|
203
|
+
return spellings;
|
|
204
|
+
}
|
|
205
|
+
spellings.push(stripped.slice(slashIndex + 1));
|
|
206
|
+
return spellings;
|
|
207
|
+
}
|
|
208
|
+
|
|
97
209
|
export function isGenericRecallExcludedPath(
|
|
98
210
|
filePath: string,
|
|
99
211
|
policy: GenericRecallPathPolicy = {},
|
|
100
212
|
source: GenericRecallPathSource = "filesystem",
|
|
101
213
|
): boolean {
|
|
102
214
|
return (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
isTopLevelArchivePath(filePath, policy, source)
|
|
107
|
-
isMeetingRecordPath(filePath)
|
|
215
|
+
isSearchExcludedPath(filePath, policy, source) ||
|
|
216
|
+
// Recall-only: archived memories are cold, but an explicit search is one
|
|
217
|
+
// of the surfaces they remain reachable through.
|
|
218
|
+
isTopLevelArchivePath(filePath, policy, source)
|
|
108
219
|
);
|
|
109
220
|
}
|
|
110
221
|
|