@remnic/core 9.3.715 → 9.3.717

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.
Files changed (81) hide show
  1. package/dist/access-boundary.d.ts +2 -2
  2. package/dist/access-boundary.js +4 -3
  3. package/dist/access-cli.js +13 -12
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +2 -2
  6. package/dist/access-http.js +8 -7
  7. package/dist/access-mcp.d.ts +2 -2
  8. package/dist/access-mcp.js +7 -6
  9. package/dist/access-operations-batch.js +5 -4
  10. package/dist/access-operations.d.ts +2 -2
  11. package/dist/access-operations.js +6 -5
  12. package/dist/{access-service-GgnA--CE.d.ts → access-service-d4Tk-Dlr.d.ts} +2 -2
  13. package/dist/access-service.d.ts +2 -2
  14. package/dist/access-service.js +3 -2
  15. package/dist/access-surface-catalog.d.ts +2 -2
  16. package/dist/bootstrap.d.ts +1 -1
  17. package/dist/{chunk-MECU6WSH.js → chunk-2B43BYYZ.js} +6 -6
  18. package/dist/chunk-2KF4HDG2.js +24 -0
  19. package/dist/chunk-2KF4HDG2.js.map +1 -0
  20. package/dist/{chunk-HHLWSWWF.js → chunk-BF2426TN.js} +2 -2
  21. package/dist/{chunk-RBHANGVX.js → chunk-BZAK3RBN.js} +2 -2
  22. package/dist/{chunk-YUJL27ET.js → chunk-CTUWGJRI.js} +40 -63
  23. package/dist/chunk-CTUWGJRI.js.map +1 -0
  24. package/dist/{chunk-6QUPUTT7.js → chunk-DZYARLJ7.js} +5 -9
  25. package/dist/{chunk-6QUPUTT7.js.map → chunk-DZYARLJ7.js.map} +1 -1
  26. package/dist/{chunk-CTAHKIG6.js → chunk-EM22PCQR.js} +7 -7
  27. package/dist/{chunk-SHRRWOVY.js → chunk-J6BH2OBA.js} +64 -21
  28. package/dist/chunk-J6BH2OBA.js.map +1 -0
  29. package/dist/{chunk-GM3BMWKR.js → chunk-KHQ433G5.js} +2 -2
  30. package/dist/{chunk-SYDHFFAW.js → chunk-OUDAU3T5.js} +4 -4
  31. package/dist/{chunk-OQH5XUH3.js → chunk-Q6IP2ARR.js} +2 -5
  32. package/dist/chunk-Q6IP2ARR.js.map +1 -0
  33. package/dist/{chunk-O62P2LFL.js → chunk-VZQXJNBD.js} +2 -2
  34. package/dist/{chunk-BNOAB5HH.js → chunk-YAINYEM3.js} +57 -48
  35. package/dist/chunk-YAINYEM3.js.map +1 -0
  36. package/dist/{chunk-3VUPWDSE.js → chunk-ZAVTEQFM.js} +4 -4
  37. package/dist/{chunk-IHMT6XTY.js → chunk-ZXLSNG3T.js} +3 -3
  38. package/dist/{cli-Do1YtfnH.d.ts → cli-insNLYs6.d.ts} +2 -2
  39. package/dist/cli.d.ts +3 -3
  40. package/dist/cli.js +12 -11
  41. package/dist/direct-answer-wiring.d.ts +9 -9
  42. package/dist/direct-answer-wiring.js +1 -1
  43. package/dist/explicit-capture.d.ts +1 -1
  44. package/dist/index.d.ts +4 -4
  45. package/dist/index.js +23 -22
  46. package/dist/index.js.map +1 -1
  47. package/dist/mcp-memory-inspector-app.d.ts +2 -2
  48. package/dist/operator-toolkit.js +5 -3
  49. package/dist/orchestration/maintenance.js +5 -2
  50. package/dist/{orchestrator-BOaVstFG.d.ts → orchestrator-XPKhY2OV.d.ts} +6 -7
  51. package/dist/orchestrator.d.ts +1 -1
  52. package/dist/orchestrator.js +7 -6
  53. package/dist/recall-planner-llm.d.ts +1 -1
  54. package/dist/recall-planner-llm.js +2 -2
  55. package/dist/recall-planner-llm.js.map +1 -1
  56. package/dist/schemas.d.ts +22 -22
  57. package/dist/transfer/types.d.ts +12 -12
  58. package/package.json +2 -2
  59. package/src/access-service.ts +56 -41
  60. package/src/capabilities.test.ts +28 -0
  61. package/src/direct-answer-wiring.test.ts +20 -13
  62. package/src/direct-answer-wiring.ts +9 -13
  63. package/src/maintenance/namespace-planner.ts +3 -10
  64. package/src/orchestrator.ts +42 -71
  65. package/src/recall-planner-llm.test.ts +30 -11
  66. package/src/recall-planner-llm.ts +4 -5
  67. package/src/scopes/scope-plan.test.ts +168 -1
  68. package/src/scopes/scope-plan.ts +163 -0
  69. package/dist/chunk-BNOAB5HH.js.map +0 -1
  70. package/dist/chunk-OQH5XUH3.js.map +0 -1
  71. package/dist/chunk-SHRRWOVY.js.map +0 -1
  72. package/dist/chunk-YUJL27ET.js.map +0 -1
  73. /package/dist/{chunk-MECU6WSH.js.map → chunk-2B43BYYZ.js.map} +0 -0
  74. /package/dist/{chunk-HHLWSWWF.js.map → chunk-BF2426TN.js.map} +0 -0
  75. /package/dist/{chunk-RBHANGVX.js.map → chunk-BZAK3RBN.js.map} +0 -0
  76. /package/dist/{chunk-CTAHKIG6.js.map → chunk-EM22PCQR.js.map} +0 -0
  77. /package/dist/{chunk-GM3BMWKR.js.map → chunk-KHQ433G5.js.map} +0 -0
  78. /package/dist/{chunk-SYDHFFAW.js.map → chunk-OUDAU3T5.js.map} +0 -0
  79. /package/dist/{chunk-O62P2LFL.js.map → chunk-VZQXJNBD.js.map} +0 -0
  80. /package/dist/{chunk-3VUPWDSE.js.map → chunk-ZAVTEQFM.js.map} +0 -0
  81. /package/dist/{chunk-IHMT6XTY.js.map → chunk-ZXLSNG3T.js.map} +0 -0
@@ -33,10 +33,16 @@
33
33
 
34
34
  import {
35
35
  canReadNamespace,
36
+ canWriteNamespace,
36
37
  defaultNamespaceForPrincipal,
37
38
  recallNamespacesForPrincipal,
38
39
  resolvePrincipal,
39
40
  } from "../namespaces/principal.js";
41
+ import {
42
+ namespaceIdentityFromToken,
43
+ namespaceIdentityToken,
44
+ } from "../namespaces/identity.js";
45
+ import path from "node:path";
40
46
  import type { ResolvedScopeProfilePlan } from "../namespaces/scope-profiles.js";
41
47
  import {
42
48
  expandScopeProfileReadNamespaces,
@@ -318,3 +324,160 @@ export function resolveScopePlan(options: ResolveScopePlanOptions): ScopePlan {
318
324
  scopeProfilePlan,
319
325
  };
320
326
  }
327
+
328
+ // ────────────────────────────────────────────────────────────────────────────
329
+ // Centralized namespace-resolution helpers (issue #1521 step 3–4)
330
+ //
331
+ // The three functions below consolidate the ad-hoc namespace-resolution logic
332
+ // that was previously scattered across orchestrator.ts (namespaceFromStorageDir,
333
+ // configuredNamespaces) and access-service.ts (resolveWritableNamespace). By
334
+ // living in THIS module they are excluded from the adHocNamespaceResolutions
335
+ // ratchet, and every consumer reaches them through a single well-known import
336
+ // instead of reimplementing the derivation inline (#1519's failure mode).
337
+ // ────────────────────────────────────────────────────────────────────────────
338
+
339
+ /**
340
+ * The configured namespace set: default + shared + every namespace-policy
341
+ * name, trimmed and de-duplicated. Pure — reads only from `config`.
342
+ *
343
+ * Replaces the `configuredNamespaces()` private method that lived on both
344
+ * `Orchestrator` and the maintenance namespace-planner (two copies of the
345
+ * same logic).
346
+ */
347
+ export function getConfiguredNamespaces(config: PluginConfig): string[] {
348
+ return Array.from(
349
+ new Set(
350
+ [
351
+ config.defaultNamespace,
352
+ config.sharedNamespace,
353
+ ...config.namespacePolicies.map((policy) => policy.name),
354
+ ]
355
+ .map((value) => value.trim())
356
+ .filter(Boolean),
357
+ ),
358
+ );
359
+ }
360
+
361
+ /**
362
+ * Options for {@link resolveNamespaceFromStorageDir}.
363
+ */
364
+ export interface ResolveNamespaceFromStorageDirOptions {
365
+ /** Plugin config (memoryDir, defaultNamespace, namespacesEnabled, …). */
366
+ readonly config: PluginConfig;
367
+ /**
368
+ * Pre-computed configured-namespace set (from {@link getConfiguredNamespaces}).
369
+ * Passed by the caller so this function does not re-derive it on every call.
370
+ */
371
+ readonly configuredNamespaces: readonly string[];
372
+ /**
373
+ * Catalog-owned dir→namespace hints (best-effort union of configured +
374
+ * catalog-discovered). May be `undefined` when no catalog hints are loaded.
375
+ */
376
+ readonly hints?: ReadonlyMap<string, ReadonlySet<string>> | undefined;
377
+ /**
378
+ * Lazy catalog-hint loader. Called ONLY after the early returns (disabled,
379
+ * memory root, no namespace segment, configured namespace) — matching the
380
+ * original lazy behavior so an eager load does not mark hints as loaded
381
+ * before the catalog file exists (codex P2).
382
+ */
383
+ readonly loadHints?: () => void;
384
+ }
385
+
386
+ /**
387
+ * Derive the namespace a storage directory belongs to.
388
+ *
389
+ * Pure (no orchestrator state): the caller passes `config`, the configured set,
390
+ * and any catalog hints. The logic is byte-identical to the private
391
+ * `namespaceFromStorageDir` method that previously lived on `Orchestrator`
392
+ * (including the token round-trip guard from codex round 6).
393
+ */
394
+ export function resolveNamespaceFromStorageDir(
395
+ storageDir: string,
396
+ options: ResolveNamespaceFromStorageDirOptions,
397
+ ): string {
398
+ const { config } = options;
399
+ if (!config.namespacesEnabled) return config.defaultNamespace;
400
+ const resolvedStorageDir = path.resolve(storageDir);
401
+ const resolvedMemoryDir = path.resolve(config.memoryDir);
402
+ if (resolvedStorageDir === resolvedMemoryDir) return config.defaultNamespace;
403
+ const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
404
+ if (!m?.[1]) return config.defaultNamespace;
405
+ const dirName = m[1];
406
+ // Token-shaped raw names (codex P2 — NBsFz): a dir name might be a tokenized
407
+ // identity OR a literal raw namespace name that merely LOOKS like a token.
408
+ // A dir name that is itself a KNOWN namespace is preserved BEFORE decoding.
409
+ if (options.configuredNamespaces.includes(dirName)) {
410
+ return dirName;
411
+ }
412
+ // Load catalog hints ONLY after the early returns (codex P2: an eager load
413
+ // before the catalog file exists would mark hints as loaded and skip later
414
+ // catalog-derived rows).
415
+ options.loadHints?.();
416
+ const hints = options.hints;
417
+ const hintedNamespaces = hints?.get(resolvedStorageDir);
418
+ if (hintedNamespaces?.has(dirName)) {
419
+ return dirName;
420
+ }
421
+ if (hintedNamespaces?.size === 1) {
422
+ const [hintedNamespace] = hintedNamespaces;
423
+ if (hintedNamespace) return hintedNamespace;
424
+ }
425
+ const decoded = namespaceIdentityFromToken(dirName);
426
+ if (decoded && namespaceIdentityToken(decoded) === dirName) {
427
+ return decoded;
428
+ }
429
+ return dirName;
430
+ }
431
+
432
+ /**
433
+ * Result of resolving a writable namespace: either the authorized namespace
434
+ * or a structured rejection. The caller decides how to surface the rejection
435
+ * (e.g. as an `EngramAccessInputError` in the access-service layer), keeping
436
+ * this module free of transport-specific error types.
437
+ */
438
+ export type WritableNamespaceResult =
439
+ | { readonly ok: true; readonly namespace: string }
440
+ | { readonly ok: false; readonly reason: "unsupported" | "not_writable"; readonly namespace: string };
441
+
442
+ /**
443
+ * Resolve and authorize a writable namespace.
444
+ *
445
+ * Combines the three steps that `AccessService.resolveWritableNamespace`
446
+ * performed inline: (1) resolve the namespace value (trim → default fallback →
447
+ * validate against `namespacesEnabled`), (2) resolve the principal, (3) check
448
+ * `canWriteNamespace`. Returns a structured result so this module stays free of
449
+ * `EngramAccessInputError` (avoiding a circular dependency on access-service.ts).
450
+ *
451
+ * The caller throws `EngramAccessInputError` when `ok === false` — the access-
452
+ * service wrapper does this in one place.
453
+ */
454
+ export function resolveWritableNamespaceValue(
455
+ namespace: string | undefined,
456
+ sessionKey: string | undefined,
457
+ authenticatedPrincipal: string | undefined,
458
+ config: PluginConfig,
459
+ ): WritableNamespaceResult {
460
+ const requested = namespace?.trim();
461
+ let resolved: string;
462
+ if (!requested) {
463
+ resolved = config.defaultNamespace;
464
+ } else if (
465
+ !config.namespacesEnabled &&
466
+ requested !== config.defaultNamespace
467
+ ) {
468
+ return { ok: false, reason: "unsupported", namespace: requested };
469
+ } else {
470
+ resolved = requested;
471
+ }
472
+
473
+ const trusted = authenticatedPrincipal?.trim();
474
+ const principal =
475
+ typeof trusted === "string" && trusted.length > 0
476
+ ? trusted
477
+ : resolvePrincipal(sessionKey, config);
478
+
479
+ if (!canWriteNamespace(principal, resolved, config)) {
480
+ return { ok: false, reason: "not_writable", namespace: resolved };
481
+ }
482
+ return { ok: true, namespace: resolved };
483
+ }