@remnic/core 9.3.645 → 9.3.646

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 (95) hide show
  1. package/dist/access-cli.js +18 -17
  2. package/dist/access-cli.js.map +1 -1
  3. package/dist/access-http.js +13 -13
  4. package/dist/access-mcp.js +10 -10
  5. package/dist/access-schema.js +3 -3
  6. package/dist/access-service.js +8 -8
  7. package/dist/adapters/index.js +4 -4
  8. package/dist/adapters/registry.js +2 -2
  9. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
  10. package/dist/{chunk-6YLJZ2EU.js → chunk-3JSWINVD.js} +92 -29
  11. package/dist/chunk-3JSWINVD.js.map +1 -0
  12. package/dist/{chunk-AGNBY3VG.js → chunk-APJQ6UEA.js} +4 -4
  13. package/dist/{chunk-HRXCPKN4.js → chunk-APWJRJFW.js} +2 -2
  14. package/dist/{chunk-VDX2J7OX.js → chunk-BUKK5SWA.js} +2 -2
  15. package/dist/{chunk-T22TZJWJ.js → chunk-DC66QVL2.js} +2 -2
  16. package/dist/chunk-EVWIEEKZ.js +315 -0
  17. package/dist/chunk-EVWIEEKZ.js.map +1 -0
  18. package/dist/{chunk-IZXOO6NP.js → chunk-FAYDM5WD.js} +2 -2
  19. package/dist/{chunk-MBT3ASYV.js → chunk-H67ZTMTL.js} +12 -12
  20. package/dist/{chunk-3SF7QNKF.js → chunk-I3IWTRYB.js} +2 -2
  21. package/dist/{chunk-Y2XKJJEI.js → chunk-IMWFHBG2.js} +10 -33
  22. package/dist/chunk-IMWFHBG2.js.map +1 -0
  23. package/dist/{chunk-IHG27THY.js → chunk-JLOJ5RJ7.js} +68 -59
  24. package/dist/chunk-JLOJ5RJ7.js.map +1 -0
  25. package/dist/{chunk-W5ISYSIL.js → chunk-L7W5YW6Y.js} +4 -4
  26. package/dist/{chunk-DGNQRNLL.js → chunk-NT5TINK5.js} +2 -2
  27. package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
  28. package/dist/{chunk-CDHRUNBX.js → chunk-QKE4LHNR.js} +2 -2
  29. package/dist/{chunk-BTRL6GG7.js → chunk-RAELB5NX.js} +5 -5
  30. package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
  31. package/dist/chunk-S4DDLTPX.js +140 -0
  32. package/dist/chunk-S4DDLTPX.js.map +1 -0
  33. package/dist/{chunk-KVUG7FF7.js → chunk-U55D5UD5.js} +7 -7
  34. package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
  35. package/dist/{chunk-D2B22JDF.js → chunk-WEPMT6SC.js} +7 -7
  36. package/dist/{chunk-YOXCJP3A.js → chunk-ZPPFKVSD.js} +3 -3
  37. package/dist/cli.js +30 -28
  38. package/dist/{first-start-migration-FF7YFGRP.js → first-start-migration-PG5HBC3K.js} +4 -4
  39. package/dist/index.d.ts +2 -0
  40. package/dist/index.js +77 -63
  41. package/dist/index.js.map +1 -1
  42. package/dist/lcm/engine.js +3 -3
  43. package/dist/lcm/index.js +11 -11
  44. package/dist/namespaces/migrate.js +5 -5
  45. package/dist/namespaces/search.js +4 -4
  46. package/dist/operator-toolkit.js +6 -6
  47. package/dist/orchestrator.js +14 -13
  48. package/dist/resume-bundles.js +3 -2
  49. package/dist/search/factory.js +3 -3
  50. package/dist/search/index.js +7 -7
  51. package/dist/session-identity.d.ts +118 -0
  52. package/dist/session-identity.js +21 -0
  53. package/dist/session-identity.js.map +1 -0
  54. package/dist/session-transcript-migration.d.ts +65 -0
  55. package/dist/session-transcript-migration.js +16 -0
  56. package/dist/session-transcript-migration.js.map +1 -0
  57. package/dist/summarizer.js +2 -1
  58. package/dist/transcript.d.ts +12 -6
  59. package/dist/transcript.js +2 -1
  60. package/dist/transfer/backup.js +2 -2
  61. package/dist/transfer/capsule-export.js +2 -2
  62. package/dist/transfer/capsule-import.js +2 -2
  63. package/dist/transfer/import-sqlite.js +2 -2
  64. package/package.json +1 -1
  65. package/src/cli.ts +79 -0
  66. package/src/index.ts +18 -0
  67. package/src/session-identity.test.ts +130 -0
  68. package/src/session-identity.ts +281 -0
  69. package/src/session-transcript-migration.test.ts +350 -0
  70. package/src/session-transcript-migration.ts +527 -0
  71. package/src/summarizer.ts +15 -35
  72. package/src/transcript-session-identity.test.ts +424 -0
  73. package/src/transcript.ts +100 -70
  74. package/dist/chunk-6YLJZ2EU.js.map +0 -1
  75. package/dist/chunk-IHG27THY.js.map +0 -1
  76. package/dist/chunk-Y2XKJJEI.js.map +0 -1
  77. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  78. /package/dist/{chunk-AGNBY3VG.js.map → chunk-APJQ6UEA.js.map} +0 -0
  79. /package/dist/{chunk-HRXCPKN4.js.map → chunk-APWJRJFW.js.map} +0 -0
  80. /package/dist/{chunk-VDX2J7OX.js.map → chunk-BUKK5SWA.js.map} +0 -0
  81. /package/dist/{chunk-T22TZJWJ.js.map → chunk-DC66QVL2.js.map} +0 -0
  82. /package/dist/{chunk-IZXOO6NP.js.map → chunk-FAYDM5WD.js.map} +0 -0
  83. /package/dist/{chunk-MBT3ASYV.js.map → chunk-H67ZTMTL.js.map} +0 -0
  84. /package/dist/{chunk-3SF7QNKF.js.map → chunk-I3IWTRYB.js.map} +0 -0
  85. /package/dist/{chunk-W5ISYSIL.js.map → chunk-L7W5YW6Y.js.map} +0 -0
  86. /package/dist/{chunk-DGNQRNLL.js.map → chunk-NT5TINK5.js.map} +0 -0
  87. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
  88. /package/dist/{chunk-CDHRUNBX.js.map → chunk-QKE4LHNR.js.map} +0 -0
  89. /package/dist/{chunk-BTRL6GG7.js.map → chunk-RAELB5NX.js.map} +0 -0
  90. /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
  91. /package/dist/{chunk-KVUG7FF7.js.map → chunk-U55D5UD5.js.map} +0 -0
  92. /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
  93. /package/dist/{chunk-D2B22JDF.js.map → chunk-WEPMT6SC.js.map} +0 -0
  94. /package/dist/{chunk-YOXCJP3A.js.map → chunk-ZPPFKVSD.js.map} +0 -0
  95. /package/dist/{first-start-migration-FF7YFGRP.js.map → first-start-migration-PG5HBC3K.js.map} +0 -0
@@ -1,3 +1,6 @@
1
+ import {
2
+ ClaudeCodeAdapter
3
+ } from "./chunk-J64TK33U.js";
1
4
  import {
2
5
  CodexAdapter
3
6
  } from "./chunk-RSUYKGGZ.js";
@@ -7,9 +10,6 @@ import {
7
10
  import {
8
11
  ReplitAdapter
9
12
  } from "./chunk-TMSXWOBZ.js";
10
- import {
11
- ClaudeCodeAdapter
12
- } from "./chunk-J64TK33U.js";
13
13
 
14
14
  // src/adapters/registry.ts
15
15
  var AdapterRegistry = class {
@@ -53,4 +53,4 @@ var AdapterRegistry = class {
53
53
  export {
54
54
  AdapterRegistry
55
55
  };
56
- //# sourceMappingURL=chunk-2QSZNTDO.js.map
56
+ //# sourceMappingURL=chunk-RKNJBZ55.js.map
@@ -0,0 +1,140 @@
1
+ import {
2
+ encodeStoragePathSegment,
3
+ encodeStoragePathSegmentWithHash,
4
+ isSafeLegacyPathSegment,
5
+ storagePathHash
6
+ } from "./chunk-FF4KLI5W.js";
7
+
8
+ // src/session-identity.ts
9
+ import path from "path";
10
+ var SESSION_CHANNEL_TYPE = "session";
11
+ var LEGACY_FALLBACK_CHANNEL_TYPE = "other";
12
+ var LEGACY_FALLBACK_CHANNEL_ID = "default";
13
+ var DISPLAY_LABEL_MAX_LENGTH = 64;
14
+ function parseSessionIdentity(sessionKey) {
15
+ const canonicalSessionKey = typeof sessionKey === "string" ? sessionKey : "";
16
+ const legacy = parseLegacyChannelIdentity(canonicalSessionKey);
17
+ if (legacy) {
18
+ return {
19
+ channelType: legacy.channelType,
20
+ channelId: legacy.channelId,
21
+ displayLabel: safeDisplayLabel(canonicalSessionKey),
22
+ canonicalSessionKey,
23
+ legacy: true
24
+ };
25
+ }
26
+ return {
27
+ channelType: SESSION_CHANNEL_TYPE,
28
+ channelId: storagePathHash(canonicalSessionKey),
29
+ displayLabel: safeDisplayLabel(canonicalSessionKey),
30
+ canonicalSessionKey,
31
+ legacy: false
32
+ };
33
+ }
34
+ function sessionStoragePaths(sessionKey) {
35
+ const identity = parseSessionIdentity(sessionKey);
36
+ const { channelType, channelId, canonicalSessionKey } = identity;
37
+ const dir = path.join(encodeStoragePathSegment(channelType), encodeStoragePathSegment(channelId));
38
+ const alternateDir = path.join(
39
+ encodeStoragePathSegmentWithHash(channelType),
40
+ `${encodeStoragePathSegmentWithHash(channelId)}--session-${storagePathHash(canonicalSessionKey)}`
41
+ );
42
+ let legacyDir;
43
+ if (isSafeLegacyPathSegment(channelType) && isSafeLegacyPathSegment(channelId)) {
44
+ const candidate = path.join(channelType, channelId);
45
+ if (candidate !== dir) {
46
+ legacyDir = candidate;
47
+ }
48
+ }
49
+ const readbackDirs = [];
50
+ if (!identity.legacy) {
51
+ const seen = /* @__PURE__ */ new Set([dir]);
52
+ if (alternateDir) seen.add(alternateDir);
53
+ if (legacyDir) seen.add(legacyDir);
54
+ for (const candidate of [OTHER_DEFAULT_READBACK_DIR, legacyParserReadbackDir(canonicalSessionKey)]) {
55
+ if (!candidate || seen.has(candidate)) continue;
56
+ seen.add(candidate);
57
+ readbackDirs.push(candidate);
58
+ }
59
+ }
60
+ return { channelType, channelId, dir, alternateDir, legacyDir, readbackDirs };
61
+ }
62
+ var OTHER_DEFAULT_READBACK_DIR = path.join(
63
+ LEGACY_FALLBACK_CHANNEL_TYPE,
64
+ LEGACY_FALLBACK_CHANNEL_ID
65
+ );
66
+ function legacyParserReadbackDir(sessionKey) {
67
+ if (typeof sessionKey !== "string" || sessionKey.length === 0) return void 0;
68
+ const parts = sessionKey.split(":");
69
+ if (parts.length < 3) return void 0;
70
+ const channelType = parts[2];
71
+ if (!channelType || channelType.length === 0) return void 0;
72
+ let channelId = LEGACY_FALLBACK_CHANNEL_ID;
73
+ if (channelType === "main") {
74
+ channelId = "default";
75
+ } else if (channelType === "discord" && parts.length >= 5 && parts[3] === "channel") {
76
+ channelId = parts[4];
77
+ } else if (channelType === "slack" && parts.length >= 5 && parts[3] === "channel") {
78
+ channelId = parts[4];
79
+ } else if (channelType === "cron" && parts.length >= 4) {
80
+ channelId = parts[3];
81
+ } else if (parts.length >= 4) {
82
+ channelId = parts[3];
83
+ }
84
+ if (!channelId || channelId.length === 0) {
85
+ channelId = LEGACY_FALLBACK_CHANNEL_ID;
86
+ }
87
+ return path.join(encodeStoragePathSegment(channelType), encodeStoragePathSegment(channelId));
88
+ }
89
+ function parseLegacyChannelIdentity(sessionKey) {
90
+ if (sessionKey.length === 0) return void 0;
91
+ const parts = sessionKey.split(":");
92
+ if (parts.length < 3) return void 0;
93
+ if (parts[0] !== "agent") return void 0;
94
+ if (!parts[1] || parts[1].length === 0) return void 0;
95
+ const channelType = parts[2];
96
+ if (!channelType || channelType.length === 0) return void 0;
97
+ let channelId = LEGACY_FALLBACK_CHANNEL_ID;
98
+ if (channelType === "main") {
99
+ channelId = "default";
100
+ } else if (channelType === "discord" && parts.length >= 5 && parts[3] === "channel") {
101
+ channelId = parts[4];
102
+ } else if (channelType === "slack" && parts.length >= 5 && parts[3] === "channel") {
103
+ channelId = parts[4];
104
+ } else if (channelType === "cron" && parts.length >= 4) {
105
+ channelId = parts[3];
106
+ } else if (parts.length >= 4) {
107
+ channelId = parts[3];
108
+ }
109
+ if (!channelId || channelId.length === 0) {
110
+ channelId = LEGACY_FALLBACK_CHANNEL_ID;
111
+ }
112
+ return { channelType, channelId };
113
+ }
114
+ function safeDisplayLabel(sessionKey) {
115
+ if (sessionKey.length === 0) return "(empty)";
116
+ let out = "";
117
+ for (const char of sessionKey) {
118
+ const code = char.codePointAt(0) ?? 0;
119
+ if (code <= 31 || code === 127) continue;
120
+ if (char === "/" || char === "\\") {
121
+ out += "_";
122
+ continue;
123
+ }
124
+ out += char;
125
+ }
126
+ const trimmed = out.trim();
127
+ if (trimmed.length === 0) return "(empty)";
128
+ return trimmed.length > DISPLAY_LABEL_MAX_LENGTH ? `${trimmed.slice(0, DISPLAY_LABEL_MAX_LENGTH - 1)}\u2026` : trimmed;
129
+ }
130
+
131
+ export {
132
+ SESSION_CHANNEL_TYPE,
133
+ LEGACY_FALLBACK_CHANNEL_TYPE,
134
+ LEGACY_FALLBACK_CHANNEL_ID,
135
+ parseSessionIdentity,
136
+ sessionStoragePaths,
137
+ OTHER_DEFAULT_READBACK_DIR,
138
+ legacyParserReadbackDir
139
+ };
140
+ //# sourceMappingURL=chunk-S4DDLTPX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session-identity.ts"],"sourcesContent":["import path from \"node:path\";\nimport {\n encodeStoragePathSegment,\n encodeStoragePathSegmentWithHash,\n isSafeLegacyPathSegment,\n storagePathHash,\n} from \"./storage-paths.js\";\n\n/**\n * Shared session-identity / transcript-pathing layer (issue #1496).\n *\n * This module is the SINGLE source of truth for turning a `sessionKey` into a\n * channel identity and a set of deterministic, collision-resistant storage\n * paths. Every subsystem that previously re-parsed session keys (transcript\n * pathing, tool-usage pathing, hourly summaries, session auditing, conversation\n * indexing) MUST route through `parseSessionIdentity()` / `sessionStoragePaths()`\n * so behavior stays identical across paths (rule #22, #39).\n *\n * Two shapes are recognized:\n *\n * 1. Legacy `agent:<agentId>:<channelType>:...` keys keep their existing\n * readable channel identity:\n * - agent:<id>:main → type=\"main\", id=\"default\"\n * - agent:<id>:discord:channel:<chanId> → type=\"discord\", id=\"<chanId>\"\n * - agent:<id>:slack:channel:<chanId> → type=\"slack\", id=\"<chanId>\"\n * - agent:<id>:cron:<jobId> → type=\"cron\", id=\"<jobId>\"\n * - agent:<id>:<other>[:<id>] → type=\"<other>\", id=\"<id?>\"\n *\n * 2. Arbitrary / non-legacy keys (e.g. `pi-geek:abc123`) become first-class\n * from the FIRST write — they NEVER start life under `other/default`:\n * channelType = \"session\"\n * channelId = storagePathHash(sessionKey) (collision-resistant)\n * yielding `transcripts/session/<hash>/YYYY-MM-DD.jsonl`.\n *\n * The reserved `\"session\"` channel type is what makes arbitrary keys isolated\n * and auditable. Legacy data under `other/default` (and any legacy channel\n * directory) remains READABLE via `legacyDir` / `alternateDir` candidates.\n */\n\n/** Channel type reserved for first-class arbitrary (non-legacy) session keys. */\nexport const SESSION_CHANNEL_TYPE = \"session\";\n\n/** Legacy fallback channel identity for un-parseable keys (read-back only). */\nexport const LEGACY_FALLBACK_CHANNEL_TYPE = \"other\";\nexport const LEGACY_FALLBACK_CHANNEL_ID = \"default\";\n\n/** Max characters of the raw session key kept in a human-readable display label. */\nconst DISPLAY_LABEL_MAX_LENGTH = 64;\n\nexport interface SessionIdentity {\n /** Channel type — legacy channel type for known shapes, else `\"session\"`. */\n channelType: string;\n /** Channel id — legacy channel id for known shapes, else the key hash. */\n channelId: string;\n /** Human-readable, non-authoritative label derived from the raw key. */\n displayLabel: string;\n /** The original session key, unchanged. */\n canonicalSessionKey: string;\n /** True when the key matched a known legacy `agent:<id>:...` shape. */\n legacy: boolean;\n}\n\nexport interface SessionStoragePaths {\n /** Channel type (mirrors {@link SessionIdentity.channelType}). */\n channelType: string;\n /** Channel id (mirrors {@link SessionIdentity.channelId}). */\n channelId: string;\n /** Primary encoded storage subdirectory: `<encodedType>/<encodedId>`. */\n dir: string;\n /**\n * Collision-resistant alternate subdirectory that always embeds the full\n * session-key hash. Used both as a write-time collision escape hatch and as a\n * read-back candidate for data written before this layer existed.\n */\n alternateDir: string;\n /**\n * Un-encoded `<type>/<id>` directory for reading data written by older\n * builds that did not URL-encode path segments. Undefined when it would be\n * identical to `dir` or when either segment is path-unsafe.\n */\n legacyDir?: string;\n /**\n * Ordered, de-duplicated list of READ-BACK-ONLY directories where an older\n * build may have stranded this key's data. NEW writes never target these —\n * they exist purely so pre-#1496 transcripts/tool-usage stay discoverable\n * (and migratable). Populated only for non-legacy keys. Includes:\n * 1. the shared `other/default` fallback (every arbitrary key landed here);\n * 2. the directory the OLD `parts.length >= 3` parser would have chosen\n * (e.g. `foo:bar:baz` → `baz/default`, `foo:bar:baz:qux` → `baz/qux`).\n * See {@link legacyParserReadbackDir}.\n */\n readbackDirs: string[];\n}\n\n/**\n * Parse a session key into a stable channel identity.\n *\n * Pure and deterministic — no filesystem access. Same input always yields the\n * same identity, which is what makes arbitrary keys collision-resistant from\n * the first write.\n */\nexport function parseSessionIdentity(sessionKey: string): SessionIdentity {\n const canonicalSessionKey = typeof sessionKey === \"string\" ? sessionKey : \"\";\n const legacy = parseLegacyChannelIdentity(canonicalSessionKey);\n if (legacy) {\n return {\n channelType: legacy.channelType,\n channelId: legacy.channelId,\n displayLabel: safeDisplayLabel(canonicalSessionKey),\n canonicalSessionKey,\n legacy: true,\n };\n }\n\n return {\n channelType: SESSION_CHANNEL_TYPE,\n channelId: storagePathHash(canonicalSessionKey),\n displayLabel: safeDisplayLabel(canonicalSessionKey),\n canonicalSessionKey,\n legacy: false,\n };\n}\n\n/**\n * Resolve the storage path pieces for a session key. Wraps\n * {@link parseSessionIdentity} so transcript, tool-usage, and summary writers\n * share one implementation (rule #22).\n */\nexport function sessionStoragePaths(sessionKey: string): SessionStoragePaths {\n const identity = parseSessionIdentity(sessionKey);\n const { channelType, channelId, canonicalSessionKey } = identity;\n\n const dir = path.join(encodeStoragePathSegment(channelType), encodeStoragePathSegment(channelId));\n\n const alternateDir = path.join(\n encodeStoragePathSegmentWithHash(channelType),\n `${encodeStoragePathSegmentWithHash(channelId)}--session-${storagePathHash(canonicalSessionKey)}`\n );\n\n let legacyDir: string | undefined;\n if (isSafeLegacyPathSegment(channelType) && isSafeLegacyPathSegment(channelId)) {\n const candidate = path.join(channelType, channelId);\n if (candidate !== dir) {\n legacyDir = candidate;\n }\n }\n\n // Read-back-only candidates are only relevant for non-legacy keys: legacy\n // `agent:<id>:...` keys still resolve to their original channel directory, so\n // nothing about their on-disk location moved.\n const readbackDirs: string[] = [];\n if (!identity.legacy) {\n const seen = new Set<string>([dir]);\n if (alternateDir) seen.add(alternateDir);\n if (legacyDir) seen.add(legacyDir);\n for (const candidate of [OTHER_DEFAULT_READBACK_DIR, legacyParserReadbackDir(canonicalSessionKey)]) {\n if (!candidate || seen.has(candidate)) continue;\n seen.add(candidate);\n readbackDirs.push(candidate);\n }\n }\n\n return { channelType, channelId, dir, alternateDir, legacyDir, readbackDirs };\n}\n\n/**\n * The shared `other/default` directory every arbitrary key was routed into by\n * builds predating issue #1496. Exposed so transcript/tool-usage/summary read\n * paths and the migration scanner all agree on the same fallback location.\n */\nexport const OTHER_DEFAULT_READBACK_DIR = path.join(\n LEGACY_FALLBACK_CHANNEL_TYPE,\n LEGACY_FALLBACK_CHANNEL_ID\n);\n\n/**\n * Reconstruct the transcript/tool-usage directory the OLD `getTranscriptPath`\n * parser (pre-#1496) would have produced for a key the NEW parser reclassifies\n * as a first-class `session/<hash>` identity.\n *\n * The OLD parser treated ANY key with `parts.length >= 3` as legacy — it did\n * NOT require a leading `agent` segment — so an arbitrary key like\n * `foo:bar:baz` was stored under `baz/default` and `foo:bar:baz:qux` under\n * `baz/qux`. Those directories must stay readable (and migratable) for existing\n * installs even though the key now writes to `session/<hash>` (Thread B / codex\n * review on PR #1504). Path segments are encoded exactly as the old `dir` was\n * built (`encodeStoragePathSegment`) so the candidate matches the bytes on disk.\n *\n * Returns `undefined` when the key has fewer than three colon parts (the old\n * parser would have used the `other/default` fallback, already covered), when\n * the channel type is empty, or when the result is unsafe.\n */\nexport function legacyParserReadbackDir(sessionKey: string): string | undefined {\n if (typeof sessionKey !== \"string\" || sessionKey.length === 0) return undefined;\n const parts = sessionKey.split(\":\");\n if (parts.length < 3) return undefined;\n\n const channelType = parts[2];\n if (!channelType || channelType.length === 0) return undefined;\n\n // Mirror the OLD parser's channelId derivation for parts.length >= 3 keys.\n let channelId = LEGACY_FALLBACK_CHANNEL_ID;\n if (channelType === \"main\") {\n channelId = \"default\";\n } else if (channelType === \"discord\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"slack\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"cron\" && parts.length >= 4) {\n channelId = parts[3];\n } else if (parts.length >= 4) {\n channelId = parts[3];\n }\n if (!channelId || channelId.length === 0) {\n channelId = LEGACY_FALLBACK_CHANNEL_ID;\n }\n\n return path.join(encodeStoragePathSegment(channelType), encodeStoragePathSegment(channelId));\n}\n\n/**\n * Parse the legacy `agent:<agentId>:<channelType>:...` shape. Returns\n * `undefined` for anything that is not a recognized legacy key, so the caller\n * can route it to a first-class `session/<hash>` identity instead.\n *\n * A legacy key must start with the literal `agent` segment and a non-empty\n * agent id; otherwise an arbitrary key like `pi-geek:abc123` would be\n * misread as `channelType = \"abc123\"`.\n */\nfunction parseLegacyChannelIdentity(sessionKey: string): { channelType: string; channelId: string } | undefined {\n if (sessionKey.length === 0) return undefined;\n const parts = sessionKey.split(\":\");\n if (parts.length < 3) return undefined;\n if (parts[0] !== \"agent\") return undefined;\n if (!parts[1] || parts[1].length === 0) return undefined;\n\n const channelType = parts[2];\n if (!channelType || channelType.length === 0) return undefined;\n\n let channelId = LEGACY_FALLBACK_CHANNEL_ID;\n if (channelType === \"main\") {\n channelId = \"default\";\n } else if (channelType === \"discord\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"slack\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"cron\" && parts.length >= 4) {\n channelId = parts[3];\n } else if (parts.length >= 4) {\n channelId = parts[3];\n }\n\n if (!channelId || channelId.length === 0) {\n channelId = LEGACY_FALLBACK_CHANNEL_ID;\n }\n\n return { channelType, channelId };\n}\n\n/**\n * A short, human-readable label for dashboards/audits. Never used for storage\n * routing — `channelId` (the hash) owns isolation. Control characters and path\n * separators are stripped so the label is safe to render.\n */\nfunction safeDisplayLabel(sessionKey: string): string {\n if (sessionKey.length === 0) return \"(empty)\";\n let out = \"\";\n for (const char of sessionKey) {\n const code = char.codePointAt(0) ?? 0;\n // Drop ASCII control characters (0x00-0x1F) and DEL (0x7F).\n if (code <= 0x1f || code === 0x7f) continue;\n if (char === \"/\" || char === \"\\\\\") {\n out += \"_\";\n continue;\n }\n out += char;\n }\n const trimmed = out.trim();\n if (trimmed.length === 0) return \"(empty)\";\n return trimmed.length > DISPLAY_LABEL_MAX_LENGTH ? `${trimmed.slice(0, DISPLAY_LABEL_MAX_LENGTH - 1)}…` : trimmed;\n}\n"],"mappings":";;;;;;;;AAAA,OAAO,UAAU;AAwCV,IAAM,uBAAuB;AAG7B,IAAM,+BAA+B;AACrC,IAAM,6BAA6B;AAG1C,IAAM,2BAA2B;AAsD1B,SAAS,qBAAqB,YAAqC;AACxE,QAAM,sBAAsB,OAAO,eAAe,WAAW,aAAa;AAC1E,QAAM,SAAS,2BAA2B,mBAAmB;AAC7D,MAAI,QAAQ;AACV,WAAO;AAAA,MACL,aAAa,OAAO;AAAA,MACpB,WAAW,OAAO;AAAA,MAClB,cAAc,iBAAiB,mBAAmB;AAAA,MAClD;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,IACb,WAAW,gBAAgB,mBAAmB;AAAA,IAC9C,cAAc,iBAAiB,mBAAmB;AAAA,IAClD;AAAA,IACA,QAAQ;AAAA,EACV;AACF;AAOO,SAAS,oBAAoB,YAAyC;AAC3E,QAAM,WAAW,qBAAqB,UAAU;AAChD,QAAM,EAAE,aAAa,WAAW,oBAAoB,IAAI;AAExD,QAAM,MAAM,KAAK,KAAK,yBAAyB,WAAW,GAAG,yBAAyB,SAAS,CAAC;AAEhG,QAAM,eAAe,KAAK;AAAA,IACxB,iCAAiC,WAAW;AAAA,IAC5C,GAAG,iCAAiC,SAAS,CAAC,aAAa,gBAAgB,mBAAmB,CAAC;AAAA,EACjG;AAEA,MAAI;AACJ,MAAI,wBAAwB,WAAW,KAAK,wBAAwB,SAAS,GAAG;AAC9E,UAAM,YAAY,KAAK,KAAK,aAAa,SAAS;AAClD,QAAI,cAAc,KAAK;AACrB,kBAAY;AAAA,IACd;AAAA,EACF;AAKA,QAAM,eAAyB,CAAC;AAChC,MAAI,CAAC,SAAS,QAAQ;AACpB,UAAM,OAAO,oBAAI,IAAY,CAAC,GAAG,CAAC;AAClC,QAAI,aAAc,MAAK,IAAI,YAAY;AACvC,QAAI,UAAW,MAAK,IAAI,SAAS;AACjC,eAAW,aAAa,CAAC,4BAA4B,wBAAwB,mBAAmB,CAAC,GAAG;AAClG,UAAI,CAAC,aAAa,KAAK,IAAI,SAAS,EAAG;AACvC,WAAK,IAAI,SAAS;AAClB,mBAAa,KAAK,SAAS;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,WAAW,KAAK,cAAc,WAAW,aAAa;AAC9E;AAOO,IAAM,6BAA6B,KAAK;AAAA,EAC7C;AAAA,EACA;AACF;AAmBO,SAAS,wBAAwB,YAAwC;AAC9E,MAAI,OAAO,eAAe,YAAY,WAAW,WAAW,EAAG,QAAO;AACtE,QAAM,QAAQ,WAAW,MAAM,GAAG;AAClC,MAAI,MAAM,SAAS,EAAG,QAAO;AAE7B,QAAM,cAAc,MAAM,CAAC;AAC3B,MAAI,CAAC,eAAe,YAAY,WAAW,EAAG,QAAO;AAGrD,MAAI,YAAY;AAChB,MAAI,gBAAgB,QAAQ;AAC1B,gBAAY;AAAA,EACd,WAAW,gBAAgB,aAAa,MAAM,UAAU,KAAK,MAAM,CAAC,MAAM,WAAW;AACnF,gBAAY,MAAM,CAAC;AAAA,EACrB,WAAW,gBAAgB,WAAW,MAAM,UAAU,KAAK,MAAM,CAAC,MAAM,WAAW;AACjF,gBAAY,MAAM,CAAC;AAAA,EACrB,WAAW,gBAAgB,UAAU,MAAM,UAAU,GAAG;AACtD,gBAAY,MAAM,CAAC;AAAA,EACrB,WAAW,MAAM,UAAU,GAAG;AAC5B,gBAAY,MAAM,CAAC;AAAA,EACrB;AACA,MAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACxC,gBAAY;AAAA,EACd;AAEA,SAAO,KAAK,KAAK,yBAAyB,WAAW,GAAG,yBAAyB,SAAS,CAAC;AAC7F;AAWA,SAAS,2BAA2B,YAA4E;AAC9G,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,QAAM,QAAQ,WAAW,MAAM,GAAG;AAClC,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,MAAI,MAAM,CAAC,MAAM,QAAS,QAAO;AACjC,MAAI,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,EAAE,WAAW,EAAG,QAAO;AAE/C,QAAM,cAAc,MAAM,CAAC;AAC3B,MAAI,CAAC,eAAe,YAAY,WAAW,EAAG,QAAO;AAErD,MAAI,YAAY;AAChB,MAAI,gBAAgB,QAAQ;AAC1B,gBAAY;AAAA,EACd,WAAW,gBAAgB,aAAa,MAAM,UAAU,KAAK,MAAM,CAAC,MAAM,WAAW;AACnF,gBAAY,MAAM,CAAC;AAAA,EACrB,WAAW,gBAAgB,WAAW,MAAM,UAAU,KAAK,MAAM,CAAC,MAAM,WAAW;AACjF,gBAAY,MAAM,CAAC;AAAA,EACrB,WAAW,gBAAgB,UAAU,MAAM,UAAU,GAAG;AACtD,gBAAY,MAAM,CAAC;AAAA,EACrB,WAAW,MAAM,UAAU,GAAG;AAC5B,gBAAY,MAAM,CAAC;AAAA,EACrB;AAEA,MAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACxC,gBAAY;AAAA,EACd;AAEA,SAAO,EAAE,aAAa,UAAU;AAClC;AAOA,SAAS,iBAAiB,YAA4B;AACpD,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,MAAI,MAAM;AACV,aAAW,QAAQ,YAAY;AAC7B,UAAM,OAAO,KAAK,YAAY,CAAC,KAAK;AAEpC,QAAI,QAAQ,MAAQ,SAAS,IAAM;AACnC,QAAI,SAAS,OAAO,SAAS,MAAM;AACjC,aAAO;AACP;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO,QAAQ,SAAS,2BAA2B,GAAG,QAAQ,MAAM,GAAG,2BAA2B,CAAC,CAAC,WAAM;AAC5G;","names":[]}
@@ -1,3 +1,9 @@
1
+ import {
2
+ NoopSearchBackend
3
+ } from "./chunk-CYEPCZN5.js";
4
+ import {
5
+ OramaBackend
6
+ } from "./chunk-DCGT4FPP.js";
1
7
  import {
2
8
  RemoteSearchBackend
3
9
  } from "./chunk-JOASJWQR.js";
@@ -10,12 +16,6 @@ import {
10
16
  import {
11
17
  MeilisearchBackend
12
18
  } from "./chunk-RG3LBSGH.js";
13
- import {
14
- NoopSearchBackend
15
- } from "./chunk-CYEPCZN5.js";
16
- import {
17
- OramaBackend
18
- } from "./chunk-DCGT4FPP.js";
19
19
  import {
20
20
  createConversationIndexBackend
21
21
  } from "./chunk-7OGJQP7T.js";
@@ -170,4 +170,4 @@ export {
170
170
  createConversationSearchBackend,
171
171
  createConversationIndexRuntime
172
172
  };
173
- //# sourceMappingURL=chunk-KVUG7FF7.js.map
173
+ //# sourceMappingURL=chunk-U55D5UD5.js.map
@@ -246,4 +246,4 @@ export {
246
246
  decryptCapsuleFile,
247
247
  decryptCapsuleFileInMemory
248
248
  };
249
- //# sourceMappingURL=chunk-DQEMWVMT.js.map
249
+ //# sourceMappingURL=chunk-UVYI6VIX.js.map
@@ -1,3 +1,9 @@
1
+ import {
2
+ LcmSummarizer
3
+ } from "./chunk-5VDJMYTF.js";
4
+ import {
5
+ LcmArchive
6
+ } from "./chunk-HP5FMB6L.js";
1
7
  import {
2
8
  LcmDag
3
9
  } from "./chunk-7N4KAIGN.js";
@@ -11,12 +17,6 @@ import {
11
17
  ensureLcmStateDir,
12
18
  openLcmDatabase
13
19
  } from "./chunk-MAV46GWQ.js";
14
- import {
15
- LcmSummarizer
16
- } from "./chunk-5VDJMYTF.js";
17
- import {
18
- LcmArchive
19
- } from "./chunk-HP5FMB6L.js";
20
20
  import {
21
21
  log
22
22
  } from "./chunk-2ODBA7MQ.js";
@@ -513,4 +513,4 @@ export {
513
513
  extractLcmConfig,
514
514
  LcmEngine
515
515
  };
516
- //# sourceMappingURL=chunk-D2B22JDF.js.map
516
+ //# sourceMappingURL=chunk-WEPMT6SC.js.map
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-D24OXEPB.js";
12
12
  import {
13
13
  EngramAccessInputError
14
- } from "./chunk-W5ISYSIL.js";
14
+ } from "./chunk-L7W5YW6Y.js";
15
15
  import {
16
16
  projectTagProjectId
17
17
  } from "./chunk-6GIKAUTN.js";
@@ -26,7 +26,7 @@ import {
26
26
  } from "./chunk-JUC24CTX.js";
27
27
  import {
28
28
  validateRequest
29
- } from "./chunk-CDHRUNBX.js";
29
+ } from "./chunk-QKE4LHNR.js";
30
30
 
31
31
  // src/access-mcp.ts
32
32
  import { readFile } from "fs/promises";
@@ -3102,4 +3102,4 @@ ${body}`;
3102
3102
  export {
3103
3103
  EngramMcpServer
3104
3104
  };
3105
- //# sourceMappingURL=chunk-YOXCJP3A.js.map
3105
+ //# sourceMappingURL=chunk-ZPPFKVSD.js.map
package/dist/cli.js CHANGED
@@ -89,40 +89,41 @@ import {
89
89
  runWorkProductStatusCliCommand,
90
90
  runWorkProjectCliCommand,
91
91
  runWorkTaskCliCommand
92
- } from "./chunk-6YLJZ2EU.js";
92
+ } from "./chunk-3JSWINVD.js";
93
93
  import "./chunk-MC4FJXPA.js";
94
94
  import "./chunk-LQHDIS7L.js";
95
95
  import "./chunk-7F7Z6MOS.js";
96
96
  import "./chunk-JJEJJ7RK.js";
97
97
  import "./chunk-HDDRVXX4.js";
98
- import "./chunk-AGNBY3VG.js";
99
- import "./chunk-UP6MOYCB.js";
100
- import "./chunk-7VFZTJ7K.js";
101
- import "./chunk-Z734BLO3.js";
98
+ import "./chunk-APJQ6UEA.js";
102
99
  import "./chunk-OZKVVUJB.js";
103
100
  import "./chunk-2DL3OFLD.js";
104
101
  import "./chunk-G4IAEX6D.js";
105
- import "./chunk-BXLOS5AJ.js";
102
+ import "./chunk-OWHERGF2.js";
103
+ import "./chunk-UP6MOYCB.js";
106
104
  import "./chunk-765K3SAT.js";
107
- import "./chunk-HOJZMQ4J.js";
108
- import "./chunk-LZZNTPLR.js";
105
+ import "./chunk-7VFZTJ7K.js";
106
+ import "./chunk-Z734BLO3.js";
109
107
  import "./chunk-EEC4PCG5.js";
110
108
  import "./chunk-PYIFUBRK.js";
111
- import "./chunk-WMWVO45V.js";
112
- import "./chunk-D6RIFG4O.js";
113
- import "./chunk-JCK7V6SN.js";
109
+ import "./chunk-HOJZMQ4J.js";
114
110
  import "./chunk-PQFUUXWK.js";
115
111
  import "./chunk-MCYT2RNT.js";
112
+ import "./chunk-LZZNTPLR.js";
113
+ import "./chunk-WMWVO45V.js";
116
114
  import "./chunk-KJTKLXTH.js";
115
+ import "./chunk-D6RIFG4O.js";
116
+ import "./chunk-JCK7V6SN.js";
117
117
  import "./chunk-CKITWVWJ.js";
118
118
  import "./chunk-OUELRE5E.js";
119
119
  import "./chunk-GQL52GQ5.js";
120
+ import "./chunk-EVWIEEKZ.js";
120
121
  import "./chunk-OTC2KOZ2.js";
121
- import "./chunk-3SF7QNKF.js";
122
+ import "./chunk-I3IWTRYB.js";
122
123
  import "./chunk-WLGE6KEO.js";
123
124
  import "./chunk-TGQ2NTWH.js";
124
- import "./chunk-T22TZJWJ.js";
125
- import "./chunk-IZXOO6NP.js";
125
+ import "./chunk-DC66QVL2.js";
126
+ import "./chunk-FAYDM5WD.js";
126
127
  import "./chunk-3T74IZB3.js";
127
128
  import "./chunk-HL4DB7TO.js";
128
129
  import "./chunk-YNDLCWXS.js";
@@ -139,7 +140,8 @@ import "./chunk-UMKPSD35.js";
139
140
  import "./chunk-W4RVMTHR.js";
140
141
  import "./chunk-4BISW7RX.js";
141
142
  import "./chunk-ZRWB5D4H.js";
142
- import "./chunk-IHG27THY.js";
143
+ import "./chunk-JLOJ5RJ7.js";
144
+ import "./chunk-S4DDLTPX.js";
143
145
  import "./chunk-SFQ6QNL7.js";
144
146
  import "./chunk-D6WVJIS3.js";
145
147
  import "./chunk-KFY3SGN7.js";
@@ -164,22 +166,22 @@ import "./chunk-Z5LAYHGJ.js";
164
166
  import "./chunk-LBJBNWS2.js";
165
167
  import "./chunk-HQ6NIBL6.js";
166
168
  import "./chunk-OADWQ5CR.js";
167
- import "./chunk-BTRL6GG7.js";
169
+ import "./chunk-RAELB5NX.js";
168
170
  import "./chunk-SEDEKFYQ.js";
169
- import "./chunk-2QSZNTDO.js";
171
+ import "./chunk-RKNJBZ55.js";
172
+ import "./chunk-J64TK33U.js";
170
173
  import "./chunk-RSUYKGGZ.js";
171
174
  import "./chunk-42NQ7AVG.js";
172
175
  import "./chunk-TMSXWOBZ.js";
173
- import "./chunk-J64TK33U.js";
174
176
  import "./chunk-7RXCMVFQ.js";
175
177
  import "./chunk-7WV3F5DQ.js";
176
- import "./chunk-YOXCJP3A.js";
178
+ import "./chunk-ZPPFKVSD.js";
177
179
  import "./chunk-T4WDJPEZ.js";
178
180
  import "./chunk-D24OXEPB.js";
179
- import "./chunk-W5ISYSIL.js";
181
+ import "./chunk-L7W5YW6Y.js";
180
182
  import "./chunk-GDASG7NC.js";
181
183
  import "./chunk-GDB4J2H3.js";
182
- import "./chunk-DGNQRNLL.js";
184
+ import "./chunk-NT5TINK5.js";
183
185
  import "./chunk-IENGGY2C.js";
184
186
  import "./chunk-SOBJ6NEY.js";
185
187
  import "./chunk-BT7NVCML.js";
@@ -190,14 +192,14 @@ import "./chunk-5RIRL3XL.js";
190
192
  import "./chunk-JGSKJHF7.js";
191
193
  import "./chunk-FF4KLI5W.js";
192
194
  import "./chunk-BEMWL2FZ.js";
193
- import "./chunk-HRXCPKN4.js";
194
- import "./chunk-KVUG7FF7.js";
195
+ import "./chunk-APWJRJFW.js";
196
+ import "./chunk-U55D5UD5.js";
197
+ import "./chunk-CYEPCZN5.js";
198
+ import "./chunk-DCGT4FPP.js";
195
199
  import "./chunk-JOASJWQR.js";
196
200
  import "./chunk-RN7MUWON.js";
197
201
  import "./chunk-3MAONBX3.js";
198
202
  import "./chunk-RG3LBSGH.js";
199
- import "./chunk-CYEPCZN5.js";
200
- import "./chunk-DCGT4FPP.js";
201
203
  import "./chunk-Q4CAQGKQ.js";
202
204
  import "./chunk-CINZGPSJ.js";
203
205
  import "./chunk-ZFXCQPNO.js";
@@ -256,10 +258,10 @@ import "./chunk-TVVEYCNW.js";
256
258
  import "./chunk-RFYAYKTD.js";
257
259
  import "./chunk-LBLXEFWK.js";
258
260
  import "./chunk-VFUEZZBS.js";
259
- import "./chunk-CDHRUNBX.js";
260
- import "./chunk-VDX2J7OX.js";
261
+ import "./chunk-QKE4LHNR.js";
262
+ import "./chunk-BUKK5SWA.js";
261
263
  import "./chunk-WEHSQBFR.js";
262
- import "./chunk-DQEMWVMT.js";
264
+ import "./chunk-UVYI6VIX.js";
263
265
  import "./chunk-J4EB7DNW.js";
264
266
  import "./chunk-BJMBJZ2Y.js";
265
267
  import "./chunk-UKJAGEXH.js";
@@ -2,12 +2,12 @@ import {
2
2
  applyUtilityPromotionRuntimePolicy,
3
3
  loadUtilityRuntimeValues
4
4
  } from "./chunk-LXOM6IQU.js";
5
- import {
6
- decideTierTransition
7
- } from "./chunk-S75M5ZRK.js";
8
5
  import {
9
6
  TierMigrationExecutor
10
7
  } from "./chunk-VOUOLGIP.js";
8
+ import {
9
+ decideTierTransition
10
+ } from "./chunk-S75M5ZRK.js";
11
11
  import "./chunk-2F6NP3NT.js";
12
12
  import "./chunk-TERNBNJB.js";
13
13
  import "./chunk-TBBDFYXW.js";
@@ -260,4 +260,4 @@ export {
260
260
  LIFECYCLE_INIT_DONE_MARKER,
261
261
  runFirstStartMigration
262
262
  };
263
- //# sourceMappingURL=first-start-migration-FF7YFGRP.js.map
263
+ //# sourceMappingURL=first-start-migration-PG5HBC3K.js.map
package/dist/index.d.ts CHANGED
@@ -38,6 +38,8 @@ export { OramaBackend } from './search/orama-backend.js';
38
38
  export { MeilisearchBackend } from './search/meilisearch-backend.js';
39
39
  export { buildEntityRecallSection } from './entity-retrieval.js';
40
40
  export { resolvePrincipal } from './namespaces/principal.js';
41
+ export { SESSION_CHANNEL_TYPE, SessionIdentity, SessionStoragePaths, legacyParserReadbackDir, parseSessionIdentity, sessionStoragePaths } from './session-identity.js';
42
+ export { storagePathHash } from './storage-paths.js';
41
43
  export { TrustZoneName, TrustZoneRecord, TrustZoneRecordKind, TrustZoneSourceClass, isTrustZoneName } from './trust-zones.js';
42
44
  export { EngramAccessHttpServer, RemnicAdminConfigPatch, RemnicAdminControls, RemnicAdminDashboardStatus, RemnicAdminFeatureStatus, RemnicAdminHarnessStatus, RemnicAdminModelOption } from './access-http.js';
43
45
  export { EngramMcpServer } from './access-mcp.js';