@remnic/core 9.3.644 → 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.
- package/dist/access-cli.js +28 -27
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.js +16 -16
- package/dist/access-mcp.js +13 -13
- package/dist/access-schema.js +3 -3
- package/dist/access-service.js +11 -11
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/briefing.js +2 -2
- package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
- package/dist/causal-consolidation.js +3 -3
- package/dist/{chunk-2GCNTHRA.js → chunk-3JSWINVD.js} +98 -35
- package/dist/chunk-3JSWINVD.js.map +1 -0
- package/dist/{chunk-SZL2GGFY.js → chunk-4BISW7RX.js} +2 -2
- package/dist/{chunk-GYITUZFT.js → chunk-A4BTPHIN.js} +171 -134
- package/dist/chunk-A4BTPHIN.js.map +1 -0
- package/dist/{chunk-NV2MGIW7.js → chunk-ALUZN7BE.js} +2 -2
- package/dist/{chunk-RFSCIBCB.js → chunk-AMACWKM4.js} +2 -2
- package/dist/{chunk-AGNBY3VG.js → chunk-APJQ6UEA.js} +4 -4
- package/dist/{chunk-HRXCPKN4.js → chunk-APWJRJFW.js} +2 -2
- package/dist/{chunk-VDX2J7OX.js → chunk-BUKK5SWA.js} +2 -2
- package/dist/{chunk-RREI7CNM.js → chunk-D6WVJIS3.js} +9 -42
- package/dist/chunk-D6WVJIS3.js.map +1 -0
- package/dist/{chunk-EGBH5IPJ.js → chunk-DC66QVL2.js} +4 -4
- package/dist/chunk-EVWIEEKZ.js +315 -0
- package/dist/chunk-EVWIEEKZ.js.map +1 -0
- package/dist/{chunk-DM4US77W.js → chunk-FAYDM5WD.js} +6 -4
- package/dist/{chunk-DM4US77W.js.map → chunk-FAYDM5WD.js.map} +1 -1
- package/dist/{chunk-3UR4SBZF.js → chunk-H67ZTMTL.js} +20 -20
- package/dist/{chunk-3SF7QNKF.js → chunk-I3IWTRYB.js} +2 -2
- package/dist/{chunk-Y2XKJJEI.js → chunk-IMWFHBG2.js} +10 -33
- package/dist/chunk-IMWFHBG2.js.map +1 -0
- package/dist/{chunk-IHG27THY.js → chunk-JLOJ5RJ7.js} +68 -59
- package/dist/chunk-JLOJ5RJ7.js.map +1 -0
- package/dist/{chunk-AK4DSORQ.js → chunk-L7W5YW6Y.js} +7 -7
- package/dist/{chunk-4HYWWO3W.js → chunk-MCYT2RNT.js} +3 -3
- package/dist/{chunk-DGNQRNLL.js → chunk-NT5TINK5.js} +2 -2
- package/dist/{chunk-THWT7RJU.js → chunk-OR7R6M5Z.js} +2 -2
- package/dist/{chunk-4MNDVDBS.js → chunk-OTC2KOZ2.js} +2 -2
- package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
- package/dist/{chunk-TTOYT5RB.js → chunk-PQFUUXWK.js} +2 -2
- package/dist/{chunk-CDHRUNBX.js → chunk-QKE4LHNR.js} +2 -2
- package/dist/{chunk-S2SEPLLA.js → chunk-RAELB5NX.js} +5 -5
- package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/chunk-S4DDLTPX.js +140 -0
- package/dist/chunk-S4DDLTPX.js.map +1 -0
- package/dist/{chunk-KVUG7FF7.js → chunk-U55D5UD5.js} +7 -7
- package/dist/{chunk-4HYLRROV.js → chunk-UMKPSD35.js} +2 -2
- package/dist/{chunk-NLPH23IQ.js → chunk-UMTG2BN2.js} +2 -2
- package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
- package/dist/{chunk-D2B22JDF.js → chunk-WEPMT6SC.js} +7 -7
- package/dist/{chunk-ECMMM2VE.js → chunk-Z3PZRDLW.js} +2 -2
- package/dist/{chunk-GJSNDJHR.js → chunk-ZPPFKVSD.js} +4 -4
- package/dist/{chunk-TKNTAUA3.js → chunk-ZXWAQFDE.js} +2 -2
- package/dist/cli.js +37 -35
- package/dist/compounding/engine.js +2 -2
- package/dist/connectors/codex-materialize-runner.js +2 -2
- package/dist/connectors/index.js +2 -2
- package/dist/entity-retrieval.js +2 -2
- package/dist/{first-start-migration-FF7YFGRP.js → first-start-migration-PG5HBC3K.js} +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +91 -78
- package/dist/index.js.map +1 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +11 -11
- package/dist/maintenance/memory-governance.js +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +3 -3
- package/dist/namespaces/migrate.js +7 -7
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.js +2 -2
- package/dist/operator-toolkit.js +9 -9
- package/dist/orchestrator.js +23 -22
- package/dist/resume-bundles.js +3 -2
- package/dist/schemas.d.ts +22 -22
- package/dist/search/factory.js +3 -3
- package/dist/search/index.js +7 -7
- package/dist/semantic-consolidation.js +3 -3
- package/dist/semantic-rule-promotion.js +2 -2
- package/dist/semantic-rule-verifier.js +2 -2
- package/dist/session-identity.d.ts +118 -0
- package/dist/session-identity.js +21 -0
- package/dist/session-identity.js.map +1 -0
- package/dist/session-transcript-migration.d.ts +65 -0
- package/dist/session-transcript-migration.js +16 -0
- package/dist/session-transcript-migration.js.map +1 -0
- package/dist/storage.js +1 -1
- package/dist/summarizer.js +2 -1
- package/dist/transcript.d.ts +12 -6
- package/dist/transcript.js +2 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/import-sqlite.js +2 -2
- package/dist/transfer/types.d.ts +12 -12
- package/dist/verified-recall.js +2 -2
- package/package.json +1 -1
- package/src/cli.ts +79 -0
- package/src/index.ts +18 -0
- package/src/session-identity.test.ts +130 -0
- package/src/session-identity.ts +281 -0
- package/src/session-transcript-migration.test.ts +350 -0
- package/src/session-transcript-migration.ts +527 -0
- package/src/storage-fallback-category-dirs.test.ts +389 -0
- package/src/storage.ts +36 -4
- package/src/summarizer.ts +15 -35
- package/src/transcript-session-identity.test.ts +424 -0
- package/src/transcript.ts +100 -70
- package/src/utils/category-dir.ts +26 -0
- package/dist/chunk-2GCNTHRA.js.map +0 -1
- package/dist/chunk-GYITUZFT.js.map +0 -1
- package/dist/chunk-IHG27THY.js.map +0 -1
- package/dist/chunk-RREI7CNM.js.map +0 -1
- package/dist/chunk-Y2XKJJEI.js.map +0 -1
- /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
- /package/dist/{chunk-SZL2GGFY.js.map → chunk-4BISW7RX.js.map} +0 -0
- /package/dist/{chunk-NV2MGIW7.js.map → chunk-ALUZN7BE.js.map} +0 -0
- /package/dist/{chunk-RFSCIBCB.js.map → chunk-AMACWKM4.js.map} +0 -0
- /package/dist/{chunk-AGNBY3VG.js.map → chunk-APJQ6UEA.js.map} +0 -0
- /package/dist/{chunk-HRXCPKN4.js.map → chunk-APWJRJFW.js.map} +0 -0
- /package/dist/{chunk-VDX2J7OX.js.map → chunk-BUKK5SWA.js.map} +0 -0
- /package/dist/{chunk-EGBH5IPJ.js.map → chunk-DC66QVL2.js.map} +0 -0
- /package/dist/{chunk-3UR4SBZF.js.map → chunk-H67ZTMTL.js.map} +0 -0
- /package/dist/{chunk-3SF7QNKF.js.map → chunk-I3IWTRYB.js.map} +0 -0
- /package/dist/{chunk-AK4DSORQ.js.map → chunk-L7W5YW6Y.js.map} +0 -0
- /package/dist/{chunk-4HYWWO3W.js.map → chunk-MCYT2RNT.js.map} +0 -0
- /package/dist/{chunk-DGNQRNLL.js.map → chunk-NT5TINK5.js.map} +0 -0
- /package/dist/{chunk-THWT7RJU.js.map → chunk-OR7R6M5Z.js.map} +0 -0
- /package/dist/{chunk-4MNDVDBS.js.map → chunk-OTC2KOZ2.js.map} +0 -0
- /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
- /package/dist/{chunk-TTOYT5RB.js.map → chunk-PQFUUXWK.js.map} +0 -0
- /package/dist/{chunk-CDHRUNBX.js.map → chunk-QKE4LHNR.js.map} +0 -0
- /package/dist/{chunk-S2SEPLLA.js.map → chunk-RAELB5NX.js.map} +0 -0
- /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-KVUG7FF7.js.map → chunk-U55D5UD5.js.map} +0 -0
- /package/dist/{chunk-4HYLRROV.js.map → chunk-UMKPSD35.js.map} +0 -0
- /package/dist/{chunk-NLPH23IQ.js.map → chunk-UMTG2BN2.js.map} +0 -0
- /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
- /package/dist/{chunk-D2B22JDF.js.map → chunk-WEPMT6SC.js.map} +0 -0
- /package/dist/{chunk-ECMMM2VE.js.map → chunk-Z3PZRDLW.js.map} +0 -0
- /package/dist/{chunk-GJSNDJHR.js.map → chunk-ZPPFKVSD.js.map} +0 -0
- /package/dist/{chunk-TKNTAUA3.js.map → chunk-ZXWAQFDE.js.map} +0 -0
- /package/dist/{first-start-migration-FF7YFGRP.js.map → first-start-migration-PG5HBC3K.js.map} +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared session-identity / transcript-pathing layer (issue #1496).
|
|
3
|
+
*
|
|
4
|
+
* This module is the SINGLE source of truth for turning a `sessionKey` into a
|
|
5
|
+
* channel identity and a set of deterministic, collision-resistant storage
|
|
6
|
+
* paths. Every subsystem that previously re-parsed session keys (transcript
|
|
7
|
+
* pathing, tool-usage pathing, hourly summaries, session auditing, conversation
|
|
8
|
+
* indexing) MUST route through `parseSessionIdentity()` / `sessionStoragePaths()`
|
|
9
|
+
* so behavior stays identical across paths (rule #22, #39).
|
|
10
|
+
*
|
|
11
|
+
* Two shapes are recognized:
|
|
12
|
+
*
|
|
13
|
+
* 1. Legacy `agent:<agentId>:<channelType>:...` keys keep their existing
|
|
14
|
+
* readable channel identity:
|
|
15
|
+
* - agent:<id>:main → type="main", id="default"
|
|
16
|
+
* - agent:<id>:discord:channel:<chanId> → type="discord", id="<chanId>"
|
|
17
|
+
* - agent:<id>:slack:channel:<chanId> → type="slack", id="<chanId>"
|
|
18
|
+
* - agent:<id>:cron:<jobId> → type="cron", id="<jobId>"
|
|
19
|
+
* - agent:<id>:<other>[:<id>] → type="<other>", id="<id?>"
|
|
20
|
+
*
|
|
21
|
+
* 2. Arbitrary / non-legacy keys (e.g. `pi-geek:abc123`) become first-class
|
|
22
|
+
* from the FIRST write — they NEVER start life under `other/default`:
|
|
23
|
+
* channelType = "session"
|
|
24
|
+
* channelId = storagePathHash(sessionKey) (collision-resistant)
|
|
25
|
+
* yielding `transcripts/session/<hash>/YYYY-MM-DD.jsonl`.
|
|
26
|
+
*
|
|
27
|
+
* The reserved `"session"` channel type is what makes arbitrary keys isolated
|
|
28
|
+
* and auditable. Legacy data under `other/default` (and any legacy channel
|
|
29
|
+
* directory) remains READABLE via `legacyDir` / `alternateDir` candidates.
|
|
30
|
+
*/
|
|
31
|
+
/** Channel type reserved for first-class arbitrary (non-legacy) session keys. */
|
|
32
|
+
declare const SESSION_CHANNEL_TYPE = "session";
|
|
33
|
+
/** Legacy fallback channel identity for un-parseable keys (read-back only). */
|
|
34
|
+
declare const LEGACY_FALLBACK_CHANNEL_TYPE = "other";
|
|
35
|
+
declare const LEGACY_FALLBACK_CHANNEL_ID = "default";
|
|
36
|
+
interface SessionIdentity {
|
|
37
|
+
/** Channel type — legacy channel type for known shapes, else `"session"`. */
|
|
38
|
+
channelType: string;
|
|
39
|
+
/** Channel id — legacy channel id for known shapes, else the key hash. */
|
|
40
|
+
channelId: string;
|
|
41
|
+
/** Human-readable, non-authoritative label derived from the raw key. */
|
|
42
|
+
displayLabel: string;
|
|
43
|
+
/** The original session key, unchanged. */
|
|
44
|
+
canonicalSessionKey: string;
|
|
45
|
+
/** True when the key matched a known legacy `agent:<id>:...` shape. */
|
|
46
|
+
legacy: boolean;
|
|
47
|
+
}
|
|
48
|
+
interface SessionStoragePaths {
|
|
49
|
+
/** Channel type (mirrors {@link SessionIdentity.channelType}). */
|
|
50
|
+
channelType: string;
|
|
51
|
+
/** Channel id (mirrors {@link SessionIdentity.channelId}). */
|
|
52
|
+
channelId: string;
|
|
53
|
+
/** Primary encoded storage subdirectory: `<encodedType>/<encodedId>`. */
|
|
54
|
+
dir: string;
|
|
55
|
+
/**
|
|
56
|
+
* Collision-resistant alternate subdirectory that always embeds the full
|
|
57
|
+
* session-key hash. Used both as a write-time collision escape hatch and as a
|
|
58
|
+
* read-back candidate for data written before this layer existed.
|
|
59
|
+
*/
|
|
60
|
+
alternateDir: string;
|
|
61
|
+
/**
|
|
62
|
+
* Un-encoded `<type>/<id>` directory for reading data written by older
|
|
63
|
+
* builds that did not URL-encode path segments. Undefined when it would be
|
|
64
|
+
* identical to `dir` or when either segment is path-unsafe.
|
|
65
|
+
*/
|
|
66
|
+
legacyDir?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Ordered, de-duplicated list of READ-BACK-ONLY directories where an older
|
|
69
|
+
* build may have stranded this key's data. NEW writes never target these —
|
|
70
|
+
* they exist purely so pre-#1496 transcripts/tool-usage stay discoverable
|
|
71
|
+
* (and migratable). Populated only for non-legacy keys. Includes:
|
|
72
|
+
* 1. the shared `other/default` fallback (every arbitrary key landed here);
|
|
73
|
+
* 2. the directory the OLD `parts.length >= 3` parser would have chosen
|
|
74
|
+
* (e.g. `foo:bar:baz` → `baz/default`, `foo:bar:baz:qux` → `baz/qux`).
|
|
75
|
+
* See {@link legacyParserReadbackDir}.
|
|
76
|
+
*/
|
|
77
|
+
readbackDirs: string[];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Parse a session key into a stable channel identity.
|
|
81
|
+
*
|
|
82
|
+
* Pure and deterministic — no filesystem access. Same input always yields the
|
|
83
|
+
* same identity, which is what makes arbitrary keys collision-resistant from
|
|
84
|
+
* the first write.
|
|
85
|
+
*/
|
|
86
|
+
declare function parseSessionIdentity(sessionKey: string): SessionIdentity;
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the storage path pieces for a session key. Wraps
|
|
89
|
+
* {@link parseSessionIdentity} so transcript, tool-usage, and summary writers
|
|
90
|
+
* share one implementation (rule #22).
|
|
91
|
+
*/
|
|
92
|
+
declare function sessionStoragePaths(sessionKey: string): SessionStoragePaths;
|
|
93
|
+
/**
|
|
94
|
+
* The shared `other/default` directory every arbitrary key was routed into by
|
|
95
|
+
* builds predating issue #1496. Exposed so transcript/tool-usage/summary read
|
|
96
|
+
* paths and the migration scanner all agree on the same fallback location.
|
|
97
|
+
*/
|
|
98
|
+
declare const OTHER_DEFAULT_READBACK_DIR: string;
|
|
99
|
+
/**
|
|
100
|
+
* Reconstruct the transcript/tool-usage directory the OLD `getTranscriptPath`
|
|
101
|
+
* parser (pre-#1496) would have produced for a key the NEW parser reclassifies
|
|
102
|
+
* as a first-class `session/<hash>` identity.
|
|
103
|
+
*
|
|
104
|
+
* The OLD parser treated ANY key with `parts.length >= 3` as legacy — it did
|
|
105
|
+
* NOT require a leading `agent` segment — so an arbitrary key like
|
|
106
|
+
* `foo:bar:baz` was stored under `baz/default` and `foo:bar:baz:qux` under
|
|
107
|
+
* `baz/qux`. Those directories must stay readable (and migratable) for existing
|
|
108
|
+
* installs even though the key now writes to `session/<hash>` (Thread B / codex
|
|
109
|
+
* review on PR #1504). Path segments are encoded exactly as the old `dir` was
|
|
110
|
+
* built (`encodeStoragePathSegment`) so the candidate matches the bytes on disk.
|
|
111
|
+
*
|
|
112
|
+
* Returns `undefined` when the key has fewer than three colon parts (the old
|
|
113
|
+
* parser would have used the `other/default` fallback, already covered), when
|
|
114
|
+
* the channel type is empty, or when the result is unsafe.
|
|
115
|
+
*/
|
|
116
|
+
declare function legacyParserReadbackDir(sessionKey: string): string | undefined;
|
|
117
|
+
|
|
118
|
+
export { LEGACY_FALLBACK_CHANNEL_ID, LEGACY_FALLBACK_CHANNEL_TYPE, OTHER_DEFAULT_READBACK_DIR, SESSION_CHANNEL_TYPE, type SessionIdentity, type SessionStoragePaths, legacyParserReadbackDir, parseSessionIdentity, sessionStoragePaths };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LEGACY_FALLBACK_CHANNEL_ID,
|
|
3
|
+
LEGACY_FALLBACK_CHANNEL_TYPE,
|
|
4
|
+
OTHER_DEFAULT_READBACK_DIR,
|
|
5
|
+
SESSION_CHANNEL_TYPE,
|
|
6
|
+
legacyParserReadbackDir,
|
|
7
|
+
parseSessionIdentity,
|
|
8
|
+
sessionStoragePaths
|
|
9
|
+
} from "./chunk-S4DDLTPX.js";
|
|
10
|
+
import "./chunk-FF4KLI5W.js";
|
|
11
|
+
import "./chunk-PZ5AY32C.js";
|
|
12
|
+
export {
|
|
13
|
+
LEGACY_FALLBACK_CHANNEL_ID,
|
|
14
|
+
LEGACY_FALLBACK_CHANNEL_TYPE,
|
|
15
|
+
OTHER_DEFAULT_READBACK_DIR,
|
|
16
|
+
SESSION_CHANNEL_TYPE,
|
|
17
|
+
legacyParserReadbackDir,
|
|
18
|
+
parseSessionIdentity,
|
|
19
|
+
sessionStoragePaths
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=session-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
interface SessionMigrationEntryGroup {
|
|
2
|
+
/** The distinct session key these lines belong to. */
|
|
3
|
+
sessionKey: string;
|
|
4
|
+
/** Whether this key is a recognized legacy `agent:<id>:...` shape. */
|
|
5
|
+
legacy: boolean;
|
|
6
|
+
/** Destination directory (relative to the transcripts root). */
|
|
7
|
+
destDir: string;
|
|
8
|
+
/** Number of JSONL entries that will move. */
|
|
9
|
+
entryCount: number;
|
|
10
|
+
}
|
|
11
|
+
interface SessionMigrationFilePlan {
|
|
12
|
+
/** Source file path (relative to transcripts root). */
|
|
13
|
+
sourceRelPath: string;
|
|
14
|
+
/** The date-stamped file name (e.g. `2026-06-29.jsonl`). */
|
|
15
|
+
fileName: string;
|
|
16
|
+
/** Distinct session groups discovered inside this source file. */
|
|
17
|
+
groups: SessionMigrationEntryGroup[];
|
|
18
|
+
/** Lines that could not be parsed as JSON or lacked a sessionKey. */
|
|
19
|
+
unmovableLines: number;
|
|
20
|
+
/**
|
|
21
|
+
* True when EVERY entry in the file already belongs in the source directory
|
|
22
|
+
* (nothing to do). Such files are skipped.
|
|
23
|
+
*/
|
|
24
|
+
alreadyHomed: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface SessionMigrationPlan {
|
|
27
|
+
generatedAt: string;
|
|
28
|
+
dryRun: boolean;
|
|
29
|
+
transcriptsDir: string;
|
|
30
|
+
/** Per-file plans that have at least one entry to move. */
|
|
31
|
+
files: SessionMigrationFilePlan[];
|
|
32
|
+
/** Distinct destination session keys across all files. */
|
|
33
|
+
distinctSessions: number;
|
|
34
|
+
/** Total entries that will be re-homed. */
|
|
35
|
+
movedEntries: number;
|
|
36
|
+
}
|
|
37
|
+
interface SessionMigrationResult {
|
|
38
|
+
plan: SessionMigrationPlan;
|
|
39
|
+
applied: boolean;
|
|
40
|
+
filesRewritten: number;
|
|
41
|
+
filesRemoved: number;
|
|
42
|
+
errors: string[];
|
|
43
|
+
manifestPath?: string;
|
|
44
|
+
}
|
|
45
|
+
interface MigrateSessionTranscriptsOptions {
|
|
46
|
+
/** The memory directory root (transcripts live under `<memoryDir>/transcripts`). */
|
|
47
|
+
memoryDir: string;
|
|
48
|
+
/** When true, perform the migration; otherwise produce a dry-run plan only. */
|
|
49
|
+
apply?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Compute the migration plan without modifying anything.
|
|
53
|
+
*/
|
|
54
|
+
declare function planSessionTranscriptMigration(options: MigrateSessionTranscriptsOptions): Promise<SessionMigrationPlan>;
|
|
55
|
+
/**
|
|
56
|
+
* Run the migration. Dry-run by default; pass `apply: true` to mutate.
|
|
57
|
+
*/
|
|
58
|
+
declare function migrateSessionTranscripts(options: MigrateSessionTranscriptsOptions): Promise<SessionMigrationResult>;
|
|
59
|
+
/** Best-effort byte-size summary for reporting (used by CLI output). */
|
|
60
|
+
declare function summarizeMigrationSources(memoryDir: string): Promise<{
|
|
61
|
+
files: number;
|
|
62
|
+
bytes: number;
|
|
63
|
+
}>;
|
|
64
|
+
|
|
65
|
+
export { type MigrateSessionTranscriptsOptions, type SessionMigrationEntryGroup, type SessionMigrationFilePlan, type SessionMigrationPlan, type SessionMigrationResult, migrateSessionTranscripts, planSessionTranscriptMigration, summarizeMigrationSources };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
migrateSessionTranscripts,
|
|
3
|
+
planSessionTranscriptMigration,
|
|
4
|
+
summarizeMigrationSources
|
|
5
|
+
} from "./chunk-EVWIEEKZ.js";
|
|
6
|
+
import "./chunk-S4DDLTPX.js";
|
|
7
|
+
import "./chunk-FF4KLI5W.js";
|
|
8
|
+
import "./chunk-6KYMPV2O.js";
|
|
9
|
+
import "./chunk-2ODBA7MQ.js";
|
|
10
|
+
import "./chunk-PZ5AY32C.js";
|
|
11
|
+
export {
|
|
12
|
+
migrateSessionTranscripts,
|
|
13
|
+
planSessionTranscriptMigration,
|
|
14
|
+
summarizeMigrationSources
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=session-transcript-migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/storage.js
CHANGED
package/dist/summarizer.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HourlySummarizer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IMWFHBG2.js";
|
|
4
4
|
import "./chunk-XJNBEDFE.js";
|
|
5
5
|
import "./chunk-XZ4WBBB5.js";
|
|
6
6
|
import "./chunk-H3HDXD3U.js";
|
|
7
|
+
import "./chunk-S4DDLTPX.js";
|
|
7
8
|
import "./chunk-A3BS64GV.js";
|
|
8
9
|
import "./chunk-B5XMS73R.js";
|
|
9
10
|
import "./chunk-7SI52C65.js";
|
package/dist/transcript.d.ts
CHANGED
|
@@ -26,13 +26,17 @@ declare class TranscriptManager {
|
|
|
26
26
|
private static readonly CHARS_PER_TOKEN;
|
|
27
27
|
constructor(config: PluginConfig);
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
* Resolve the storage path pieces for a sessionKey via the shared
|
|
30
|
+
* {@link sessionStoragePaths} helper (issue #1496, rule #22).
|
|
30
31
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* Legacy `agent:<id>:...` shapes keep their existing readable channel paths.
|
|
33
|
+
* Arbitrary / non-legacy keys (e.g. `pi-geek:abc123`) route to
|
|
34
|
+
* `transcripts/session/<hash>/YYYY-MM-DD.jsonl` from the FIRST write — they
|
|
35
|
+
* never start life in `other/default`. For those keys a list of
|
|
36
|
+
* read-back-only `readbackDirs` is returned so data written by older builds
|
|
37
|
+
* (under `other/default`, or under an old `parts.length >= 3` directory such
|
|
38
|
+
* as `baz/default`) stays discoverable until migrated. New writes never
|
|
39
|
+
* target read-back dirs. See `session-identity.ts`.
|
|
36
40
|
*
|
|
37
41
|
* @returns Object with raw channel identifiers and encoded storage path pieces.
|
|
38
42
|
*/
|
|
@@ -43,6 +47,7 @@ declare class TranscriptManager {
|
|
|
43
47
|
channelId: string;
|
|
44
48
|
alternateDir: string;
|
|
45
49
|
legacyDir?: string;
|
|
50
|
+
readbackDirs: string[];
|
|
46
51
|
};
|
|
47
52
|
/**
|
|
48
53
|
* Initialize the transcript manager by ensuring directories exist.
|
|
@@ -59,6 +64,7 @@ declare class TranscriptManager {
|
|
|
59
64
|
file: string;
|
|
60
65
|
alternateDir: string;
|
|
61
66
|
legacyDir?: string;
|
|
67
|
+
readbackDirs: string[];
|
|
62
68
|
};
|
|
63
69
|
private selectStorageDirForWrite;
|
|
64
70
|
private directorySessionStatus;
|
package/dist/transcript.js
CHANGED
package/dist/transfer/backup.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
backupMemoryDir
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-OWHERGF2.js";
|
|
4
4
|
import "../chunk-765K3SAT.js";
|
|
5
|
-
import "../chunk-
|
|
5
|
+
import "../chunk-UVYI6VIX.js";
|
|
6
6
|
import "../chunk-J4EB7DNW.js";
|
|
7
7
|
import "../chunk-BJMBJZ2Y.js";
|
|
8
8
|
import "../chunk-UKJAGEXH.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
exportCapsule,
|
|
3
3
|
isValidCapsuleSince
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-BUKK5SWA.js";
|
|
5
5
|
import "../chunk-WEHSQBFR.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-UVYI6VIX.js";
|
|
7
7
|
import "../chunk-J4EB7DNW.js";
|
|
8
8
|
import "../chunk-BJMBJZ2Y.js";
|
|
9
9
|
import "../chunk-UKJAGEXH.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
importCapsule
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-NT5TINK5.js";
|
|
4
4
|
import "../chunk-ALEPI75L.js";
|
|
5
5
|
import "../chunk-WEHSQBFR.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-UVYI6VIX.js";
|
|
7
7
|
import "../chunk-BJMBJZ2Y.js";
|
|
8
8
|
import "../chunk-UKJAGEXH.js";
|
|
9
9
|
import "../chunk-FP2373TW.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
importSqlite
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-Z734BLO3.js";
|
|
3
|
+
} from "../chunk-APJQ6UEA.js";
|
|
5
4
|
import "../chunk-G4IAEX6D.js";
|
|
5
|
+
import "../chunk-Z734BLO3.js";
|
|
6
6
|
import "../chunk-6KYMPV2O.js";
|
|
7
7
|
import "../chunk-GCGJW34D.js";
|
|
8
8
|
import "../chunk-PZ5AY32C.js";
|
package/dist/transfer/types.d.ts
CHANGED
|
@@ -313,13 +313,13 @@ declare const CapsuleBlockSchema: z.ZodObject<{
|
|
|
313
313
|
peerProfiles: boolean;
|
|
314
314
|
}>;
|
|
315
315
|
}, "strip", z.ZodTypeAny, {
|
|
316
|
+
schemaVersion: string;
|
|
316
317
|
includes: {
|
|
317
318
|
procedural: boolean;
|
|
318
319
|
taxonomy: boolean;
|
|
319
320
|
identityAnchors: boolean;
|
|
320
321
|
peerProfiles: boolean;
|
|
321
322
|
};
|
|
322
|
-
schemaVersion: string;
|
|
323
323
|
id: string;
|
|
324
324
|
description: string;
|
|
325
325
|
version: string;
|
|
@@ -334,13 +334,13 @@ declare const CapsuleBlockSchema: z.ZodObject<{
|
|
|
334
334
|
directAnswerEnabled: boolean;
|
|
335
335
|
};
|
|
336
336
|
}, {
|
|
337
|
+
schemaVersion: string;
|
|
337
338
|
includes: {
|
|
338
339
|
procedural: boolean;
|
|
339
340
|
taxonomy: boolean;
|
|
340
341
|
identityAnchors: boolean;
|
|
341
342
|
peerProfiles: boolean;
|
|
342
343
|
};
|
|
343
|
-
schemaVersion: string;
|
|
344
344
|
id: string;
|
|
345
345
|
description: string;
|
|
346
346
|
version: string;
|
|
@@ -464,13 +464,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
464
464
|
peerProfiles: boolean;
|
|
465
465
|
}>;
|
|
466
466
|
}, "strip", z.ZodTypeAny, {
|
|
467
|
+
schemaVersion: string;
|
|
467
468
|
includes: {
|
|
468
469
|
procedural: boolean;
|
|
469
470
|
taxonomy: boolean;
|
|
470
471
|
identityAnchors: boolean;
|
|
471
472
|
peerProfiles: boolean;
|
|
472
473
|
};
|
|
473
|
-
schemaVersion: string;
|
|
474
474
|
id: string;
|
|
475
475
|
description: string;
|
|
476
476
|
version: string;
|
|
@@ -485,13 +485,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
485
485
|
directAnswerEnabled: boolean;
|
|
486
486
|
};
|
|
487
487
|
}, {
|
|
488
|
+
schemaVersion: string;
|
|
488
489
|
includes: {
|
|
489
490
|
procedural: boolean;
|
|
490
491
|
taxonomy: boolean;
|
|
491
492
|
identityAnchors: boolean;
|
|
492
493
|
peerProfiles: boolean;
|
|
493
494
|
};
|
|
494
|
-
schemaVersion: string;
|
|
495
495
|
id: string;
|
|
496
496
|
description: string;
|
|
497
497
|
version: string;
|
|
@@ -518,13 +518,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
518
518
|
pluginVersion: string;
|
|
519
519
|
includesTranscripts: boolean;
|
|
520
520
|
capsule: {
|
|
521
|
+
schemaVersion: string;
|
|
521
522
|
includes: {
|
|
522
523
|
procedural: boolean;
|
|
523
524
|
taxonomy: boolean;
|
|
524
525
|
identityAnchors: boolean;
|
|
525
526
|
peerProfiles: boolean;
|
|
526
527
|
};
|
|
527
|
-
schemaVersion: string;
|
|
528
528
|
id: string;
|
|
529
529
|
description: string;
|
|
530
530
|
version: string;
|
|
@@ -551,13 +551,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
551
551
|
pluginVersion: string;
|
|
552
552
|
includesTranscripts: boolean;
|
|
553
553
|
capsule: {
|
|
554
|
+
schemaVersion: string;
|
|
554
555
|
includes: {
|
|
555
556
|
procedural: boolean;
|
|
556
557
|
taxonomy: boolean;
|
|
557
558
|
identityAnchors: boolean;
|
|
558
559
|
peerProfiles: boolean;
|
|
559
560
|
};
|
|
560
|
-
schemaVersion: string;
|
|
561
561
|
id: string;
|
|
562
562
|
description: string;
|
|
563
563
|
version: string;
|
|
@@ -683,13 +683,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
683
683
|
peerProfiles: boolean;
|
|
684
684
|
}>;
|
|
685
685
|
}, "strip", z.ZodTypeAny, {
|
|
686
|
+
schemaVersion: string;
|
|
686
687
|
includes: {
|
|
687
688
|
procedural: boolean;
|
|
688
689
|
taxonomy: boolean;
|
|
689
690
|
identityAnchors: boolean;
|
|
690
691
|
peerProfiles: boolean;
|
|
691
692
|
};
|
|
692
|
-
schemaVersion: string;
|
|
693
693
|
id: string;
|
|
694
694
|
description: string;
|
|
695
695
|
version: string;
|
|
@@ -704,13 +704,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
704
704
|
directAnswerEnabled: boolean;
|
|
705
705
|
};
|
|
706
706
|
}, {
|
|
707
|
+
schemaVersion: string;
|
|
707
708
|
includes: {
|
|
708
709
|
procedural: boolean;
|
|
709
710
|
taxonomy: boolean;
|
|
710
711
|
identityAnchors: boolean;
|
|
711
712
|
peerProfiles: boolean;
|
|
712
713
|
};
|
|
713
|
-
schemaVersion: string;
|
|
714
714
|
id: string;
|
|
715
715
|
description: string;
|
|
716
716
|
version: string;
|
|
@@ -737,13 +737,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
737
737
|
pluginVersion: string;
|
|
738
738
|
includesTranscripts: boolean;
|
|
739
739
|
capsule: {
|
|
740
|
+
schemaVersion: string;
|
|
740
741
|
includes: {
|
|
741
742
|
procedural: boolean;
|
|
742
743
|
taxonomy: boolean;
|
|
743
744
|
identityAnchors: boolean;
|
|
744
745
|
peerProfiles: boolean;
|
|
745
746
|
};
|
|
746
|
-
schemaVersion: string;
|
|
747
747
|
id: string;
|
|
748
748
|
description: string;
|
|
749
749
|
version: string;
|
|
@@ -770,13 +770,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
770
770
|
pluginVersion: string;
|
|
771
771
|
includesTranscripts: boolean;
|
|
772
772
|
capsule: {
|
|
773
|
+
schemaVersion: string;
|
|
773
774
|
includes: {
|
|
774
775
|
procedural: boolean;
|
|
775
776
|
taxonomy: boolean;
|
|
776
777
|
identityAnchors: boolean;
|
|
777
778
|
peerProfiles: boolean;
|
|
778
779
|
};
|
|
779
|
-
schemaVersion: string;
|
|
780
780
|
id: string;
|
|
781
781
|
description: string;
|
|
782
782
|
version: string;
|
|
@@ -815,13 +815,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
815
815
|
pluginVersion: string;
|
|
816
816
|
includesTranscripts: boolean;
|
|
817
817
|
capsule: {
|
|
818
|
+
schemaVersion: string;
|
|
818
819
|
includes: {
|
|
819
820
|
procedural: boolean;
|
|
820
821
|
taxonomy: boolean;
|
|
821
822
|
identityAnchors: boolean;
|
|
822
823
|
peerProfiles: boolean;
|
|
823
824
|
};
|
|
824
|
-
schemaVersion: string;
|
|
825
825
|
id: string;
|
|
826
826
|
description: string;
|
|
827
827
|
version: string;
|
|
@@ -854,13 +854,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
854
854
|
pluginVersion: string;
|
|
855
855
|
includesTranscripts: boolean;
|
|
856
856
|
capsule: {
|
|
857
|
+
schemaVersion: string;
|
|
857
858
|
includes: {
|
|
858
859
|
procedural: boolean;
|
|
859
860
|
taxonomy: boolean;
|
|
860
861
|
identityAnchors: boolean;
|
|
861
862
|
peerProfiles: boolean;
|
|
862
863
|
};
|
|
863
|
-
schemaVersion: string;
|
|
864
864
|
id: string;
|
|
865
865
|
description: string;
|
|
866
866
|
version: string;
|
package/dist/verified-recall.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
searchVerifiedEpisodes
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UMKPSD35.js";
|
|
4
4
|
import "./chunk-HQ6NIBL6.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-A4BTPHIN.js";
|
|
6
6
|
import "./chunk-M7XQSUBB.js";
|
|
7
7
|
import "./chunk-5UZXUTVO.js";
|
|
8
8
|
import "./chunk-J6A3CX5N.js";
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -202,6 +202,10 @@ import {
|
|
|
202
202
|
type SessionRepairApplyResult,
|
|
203
203
|
type SessionRepairPlan,
|
|
204
204
|
} from "./session-integrity.js";
|
|
205
|
+
import {
|
|
206
|
+
migrateSessionTranscripts,
|
|
207
|
+
planSessionTranscriptMigration,
|
|
208
|
+
} from "./session-transcript-migration.js";
|
|
205
209
|
import type { TierMigrationCycleSummary, TierMigrationStatusSnapshot } from "./recall-state.js";
|
|
206
210
|
import {
|
|
207
211
|
readRuntimePolicySnapshot as readPolicyRuntimeSnapshot,
|
|
@@ -8650,6 +8654,81 @@ export function registerCli(
|
|
|
8650
8654
|
}
|
|
8651
8655
|
});
|
|
8652
8656
|
|
|
8657
|
+
// ── Sessions subcommand (issue #1496) ───────────────────────────────
|
|
8658
|
+
const sessionsCmd = cmd
|
|
8659
|
+
.command("sessions")
|
|
8660
|
+
.description("Inspect and migrate session transcript storage");
|
|
8661
|
+
|
|
8662
|
+
sessionsCmd
|
|
8663
|
+
.command("migrate-transcripts")
|
|
8664
|
+
.description(
|
|
8665
|
+
"Split conflated other/default transcripts into first-class session/<hash> dirs",
|
|
8666
|
+
)
|
|
8667
|
+
.option("--dry-run", "Report the migration plan without moving files (default)")
|
|
8668
|
+
.option("--apply", "Apply the migration (move files; default is dry-run)")
|
|
8669
|
+
.action(async (...args: unknown[]) => {
|
|
8670
|
+
const options = (args[0] ?? {}) as Record<string, unknown>;
|
|
8671
|
+
const dryRunFlag = options.dryRun === true;
|
|
8672
|
+
const applyFlag = options.apply === true;
|
|
8673
|
+
|
|
8674
|
+
// Rule #51: reject contradictory flags rather than silently picking one.
|
|
8675
|
+
if (dryRunFlag && applyFlag) {
|
|
8676
|
+
console.error("Cannot pass both --dry-run and --apply. Choose one.");
|
|
8677
|
+
process.exit(1);
|
|
8678
|
+
}
|
|
8679
|
+
|
|
8680
|
+
// Safe default: dry-run when neither flag is given.
|
|
8681
|
+
const apply = applyFlag;
|
|
8682
|
+
const memoryDir = orchestrator.config.memoryDir;
|
|
8683
|
+
|
|
8684
|
+
if (!apply) {
|
|
8685
|
+
const plan = await planSessionTranscriptMigration({ memoryDir });
|
|
8686
|
+
console.log("=== Session Transcript Migration (DRY RUN) ===\n");
|
|
8687
|
+
if (!dryRunFlag && !applyFlag) {
|
|
8688
|
+
console.log("No flag given — defaulting to --dry-run. Pass --apply to migrate.\n");
|
|
8689
|
+
}
|
|
8690
|
+
console.log(`transcripts dir: ${plan.transcriptsDir}`);
|
|
8691
|
+
console.log(`files to migrate: ${plan.files.length}`);
|
|
8692
|
+
console.log(`distinct sessions: ${plan.distinctSessions}`);
|
|
8693
|
+
console.log(`entries to move: ${plan.movedEntries}`);
|
|
8694
|
+
if (plan.files.length > 0) {
|
|
8695
|
+
console.log("\nPlanned splits:");
|
|
8696
|
+
for (const file of plan.files) {
|
|
8697
|
+
console.log(`- ${file.sourceRelPath}`);
|
|
8698
|
+
for (const group of file.groups) {
|
|
8699
|
+
console.log(
|
|
8700
|
+
` ${group.entryCount} entr${group.entryCount === 1 ? "y" : "ies"} → ${group.destDir} (${group.legacy ? "legacy" : "session"})`,
|
|
8701
|
+
);
|
|
8702
|
+
}
|
|
8703
|
+
if (file.unmovableLines > 0) {
|
|
8704
|
+
console.log(` ${file.unmovableLines} unmovable line(s) retained in source`);
|
|
8705
|
+
}
|
|
8706
|
+
}
|
|
8707
|
+
}
|
|
8708
|
+
console.log("\nDRY RUN — no files changed.");
|
|
8709
|
+
return;
|
|
8710
|
+
}
|
|
8711
|
+
|
|
8712
|
+
const result = await migrateSessionTranscripts({ memoryDir, apply: true });
|
|
8713
|
+
console.log("=== Session Transcript Migration (APPLY) ===\n");
|
|
8714
|
+
console.log(`files rewritten: ${result.filesRewritten}`);
|
|
8715
|
+
console.log(`files removed: ${result.filesRemoved}`);
|
|
8716
|
+
console.log(`distinct sessions: ${result.plan.distinctSessions}`);
|
|
8717
|
+
console.log(`entries moved: ${result.plan.movedEntries}`);
|
|
8718
|
+
if (result.manifestPath) {
|
|
8719
|
+
console.log(`manifest: ${result.manifestPath}`);
|
|
8720
|
+
}
|
|
8721
|
+
if (result.errors.length > 0) {
|
|
8722
|
+
console.log("\nErrors:");
|
|
8723
|
+
for (const err of result.errors) {
|
|
8724
|
+
console.log(`- ${err}`);
|
|
8725
|
+
}
|
|
8726
|
+
process.exitCode = 1;
|
|
8727
|
+
return;
|
|
8728
|
+
}
|
|
8729
|
+
console.log("\nOK");
|
|
8730
|
+
});
|
|
8731
|
+
|
|
8653
8732
|
// Checkpoint command
|
|
8654
8733
|
cmd
|
|
8655
8734
|
.command("checkpoint")
|
package/src/index.ts
CHANGED
|
@@ -324,6 +324,24 @@ export { MeilisearchBackend } from "./search/meilisearch-backend.js";
|
|
|
324
324
|
export { buildEntityRecallSection } from "./entity-retrieval.js";
|
|
325
325
|
export { resolvePrincipal } from "./namespaces/principal.js";
|
|
326
326
|
|
|
327
|
+
// ---------------------------------------------------------------------------
|
|
328
|
+
// Session identity / transcript pathing (issue #1496)
|
|
329
|
+
// ---------------------------------------------------------------------------
|
|
330
|
+
|
|
331
|
+
// Shared, deterministic session-key → storage-path resolution. Exported so
|
|
332
|
+
// downstream consumers (the @remnic/bench adapter + its tests, host adapters)
|
|
333
|
+
// resolve transcript directories through the SAME layer the core writer uses
|
|
334
|
+
// instead of hard-coding `other/default` (rule #20, #22, #26).
|
|
335
|
+
export {
|
|
336
|
+
SESSION_CHANNEL_TYPE,
|
|
337
|
+
parseSessionIdentity,
|
|
338
|
+
sessionStoragePaths,
|
|
339
|
+
legacyParserReadbackDir,
|
|
340
|
+
type SessionIdentity,
|
|
341
|
+
type SessionStoragePaths,
|
|
342
|
+
} from "./session-identity.js";
|
|
343
|
+
export { storagePathHash } from "./storage-paths.js";
|
|
344
|
+
|
|
327
345
|
// ---------------------------------------------------------------------------
|
|
328
346
|
// Trust zones
|
|
329
347
|
// ---------------------------------------------------------------------------
|