@dsh-electron/dsh-plugin-multi-root-workspace 0.1.13 → 0.1.15
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/CHANGELOG.en.md +36 -1
- package/CHANGELOG.md +36 -1
- package/README.en.md +27 -10
- package/README.md +27 -10
- package/cordis.patch.yml +5 -1
- package/detail/DETAIL.en.md +1 -0
- package/detail/DETAIL.md +1 -0
- package/detail/preview.svg +1 -0
- package/detail/preview.zh.svg +1 -0
- package/lib/{llm-message-fYORacvh.js → agent-instructions-BXuKhOzr.js} +1 -84
- package/lib/auto-review.js +2 -2
- package/lib/client.js +584 -73
- package/lib/client.js.map +1 -1
- package/lib/{command-B9855H7y.js → command-y5tfcAeC.js} +45 -12
- package/lib/command.js +1 -1
- package/lib/compat-CTJbpCxu.js +267 -0
- package/lib/compat.js +1 -1
- package/lib/{dialects-Dr4rDR-H.js → dialects-CdlG3RF9.js} +1 -1
- package/lib/{compat-Bg2HFVMX.js → dsh-version-DCwF7REk.js} +5 -265
- package/lib/{fs-CfzJq2wd.js → fs-Uws0ZpmV.js} +38 -0
- package/lib/fs.js +1 -1
- package/lib/index.js +11 -9
- package/lib/{instructions-KsUwUFE0.js → instructions-Ck9wp4J4.js} +695 -26
- package/lib/instructions.js +1 -1
- package/lib/llm-message-CepyzEBQ.js +84 -0
- package/lib/lsp.js +3 -3
- package/lib/{metadata-DgqSdVX_.js → metadata-99jgViHQ.js} +1 -1
- package/lib/{method-wrapper-CFY3p3j2.js → method-wrapper-D4oUCsEF.js} +22 -2
- package/lib/{native-win32-2waCRkPI.js → native-win32-C5oMtt7f.js} +2 -1
- package/lib/ops-compatibility.js +58 -0
- package/lib/ops-settings-UN2oOKEp.js +40 -0
- package/lib/ops-tools-k4JYaOrM.js +152 -0
- package/lib/process-fence.js +100 -24
- package/lib/{protocol-CJOvAvOS.js → protocol-CwDnFEyK.js} +54 -8
- package/lib/{registry-Bv431TfO.js → registry-DyDNDSJZ.js} +235 -79
- package/lib/{registry-lease-win32-DVTq9d4D.js → registry-lease-win32-r4puac9m.js} +2 -1
- package/lib/registry.js +2 -2
- package/lib/{review-context-NDpKeMCc.js → review-context-B-oHkU6a.js} +24 -7
- package/lib/review-context.js +1 -1
- package/lib/{roots-Ca_W1S9n.js → roots-CmaWxRVy.js} +112 -22
- package/lib/{sandbox-C-vCJCp3.js → sandbox-CZElTNPz.js} +1 -1
- package/lib/sandbox.js +1 -1
- package/lib/scope.js +72 -9
- package/lib/skills-utyuvmwr.js +104 -0
- package/lib/skills.js +4 -105
- package/lib/{tool-context-CpgIFcCB.js → tool-context-CCeY3mrK.js} +1 -1
- package/lib/types/authority/protocol.d.ts +5 -1
- package/lib/types/client/RootSwitcher.d.ts +2 -0
- package/lib/types/client/auto-review-settings.d.ts +18 -0
- package/lib/types/client/files-tree/FilesTree.d.ts +4 -1
- package/lib/types/client/files-tree/locales.d.ts +1 -1
- package/lib/types/client/locales.d.ts +40 -0
- package/lib/types/client/open-in-app/locales.d.ts +1 -1
- package/lib/types/client/ops-settings.d.ts +6 -0
- package/lib/types/client/skills-settings.d.ts +13 -0
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/command.d.ts +3 -3
- package/lib/types/compat/auto-review-client.d.ts +58 -0
- package/lib/types/compat/connection-rpc.d.ts +12 -0
- package/lib/types/compat/dsh-version.d.ts +1 -1
- package/lib/types/compat/files-tree.d.ts +36 -0
- package/lib/types/compat/fs-patch.d.ts +6 -0
- package/lib/types/compat/instruction-activity.d.ts +32 -1
- package/lib/types/compat/koffi.d.ts +2 -0
- package/lib/types/compat/ops-confirmation.d.ts +17 -0
- package/lib/types/compat/ops-settings.d.ts +11 -0
- package/lib/types/compat/ops-tools.d.ts +25 -0
- package/lib/types/compat/skills-client.d.ts +1 -0
- package/lib/types/compat/tool-context.d.ts +4 -0
- package/lib/types/compat.d.ts +2 -2
- package/lib/types/fs.d.ts +3 -1
- package/lib/types/instructions.d.ts +6 -1
- package/lib/types/ops-compatibility.d.ts +34 -0
- package/lib/types/registry.d.ts +67 -8
- package/lib/types/review-context.d.ts +2 -0
- package/lib/types/roots.d.ts +114 -20
- package/lib/types/scope.d.ts +28 -2
- package/lib/workspace-files.js +3 -3
- package/lib/{workspace-routing-YPxaQ4V3.js → workspace-routing-D_qwMUh-.js} +4 -4
- package/locale/en.json +7 -0
- package/locale/zh.json +7 -0
- package/package.json +93 -82
- package/src/auto-review/README.en.md +1 -1
- package/src/auto-review/README.md +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as runPrimaryOperation, n as freezeOperationScope, o as runRegistryOperation } from "./registry-operation-C2ZV3Jhw.js";
|
|
2
2
|
import { i as isWindowsNetworkOrDevicePath } from "./windows-runner-contract-B5R2K3mM.js";
|
|
3
|
-
import { a as classifyStoredRoots, d as
|
|
4
|
-
import { r as validateAliasId, t as migrateRootSkills } from "./metadata-
|
|
5
|
-
import { a as snapshotSchema, i as parseArguments, r as AuthorityServer, s as storeIdentity, t as AuthorityClient } from "./protocol-
|
|
3
|
+
import { _ as samePath, a as classifyStoredRoots, d as primaryKey, f as protectedOverlap, h as resolveRootIndex, i as canonicalRoot, m as reservedRootBoundary, n as additionalRootId, p as removeStatusAt, s as expandRootInput, t as RootValidationError, u as markProtectedPaths, v as singleGrantOf, y as validateRootCandidate } from "./roots-CmaWxRVy.js";
|
|
4
|
+
import { r as validateAliasId, t as migrateRootSkills } from "./metadata-99jgViHQ.js";
|
|
5
|
+
import { a as snapshotSchema, i as parseArguments, r as AuthorityServer, s as storeIdentity, t as AuthorityClient } from "./protocol-CwDnFEyK.js";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { closeSync, fstatSync, mkdirSync, openSync, statSync } from "node:fs";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
@@ -265,7 +265,7 @@ var RegistryAuthorityLease = class RegistryAuthorityLease {
|
|
|
265
265
|
mode: 448
|
|
266
266
|
});
|
|
267
267
|
if (process.platform === "win32") {
|
|
268
|
-
const { acquireLockHandleWin32 } = await import("./registry-lease-win32-
|
|
268
|
+
const { acquireLockHandleWin32 } = await import("./registry-lease-win32-r4puac9m.js");
|
|
269
269
|
let handle;
|
|
270
270
|
try {
|
|
271
271
|
handle = await acquireLockHandleWin32(leasePath);
|
|
@@ -317,7 +317,7 @@ var RegistryAuthorityLease = class RegistryAuthorityLease {
|
|
|
317
317
|
if (this.released) return;
|
|
318
318
|
this.released = true;
|
|
319
319
|
if (this.held.kind === "win32") {
|
|
320
|
-
const { releaseLockHandleWin32 } = await import("./registry-lease-win32-
|
|
320
|
+
const { releaseLockHandleWin32 } = await import("./registry-lease-win32-r4puac9m.js");
|
|
321
321
|
await releaseLockHandleWin32(this.held.handle);
|
|
322
322
|
return;
|
|
323
323
|
}
|
|
@@ -430,11 +430,11 @@ const multiRootDomainSpec = defineDomain({
|
|
|
430
430
|
tables: { roots: domainTable(persistedPrimaryRoot) }
|
|
431
431
|
});
|
|
432
432
|
/** The registry service: `ctx.multiRootRegistry`. */
|
|
433
|
-
var MultiRootRegistry = class extends Service {
|
|
433
|
+
var MultiRootRegistry = class MultiRootRegistry extends Service {
|
|
434
434
|
static inject = [
|
|
435
435
|
"multiRootCompat",
|
|
436
436
|
"multiRootProviders",
|
|
437
|
-
"
|
|
437
|
+
"storage",
|
|
438
438
|
"multiRootScope"
|
|
439
439
|
];
|
|
440
440
|
/** Absolute lock path; absent means the row was composed without `leasePath`. */
|
|
@@ -492,8 +492,15 @@ var MultiRootRegistry = class extends Service {
|
|
|
492
492
|
/** Keys already warned about a historical over-limit store (one warning each). */
|
|
493
493
|
warnedOverLimit = /* @__PURE__ */ new Set();
|
|
494
494
|
/**
|
|
495
|
-
*
|
|
496
|
-
*
|
|
495
|
+
* The canonical value each protected boundary resolved to the FIRST time it
|
|
496
|
+
* could be computed, keyed by boundary kind. Never re-pinned: a later
|
|
497
|
+
* rename or symlink swap of the DSH home (or of the lease directory) must
|
|
498
|
+
* not drop the boundary the registration rules were enforced under.
|
|
499
|
+
*/
|
|
500
|
+
pinnedProtectedPaths = /* @__PURE__ */ new Map();
|
|
501
|
+
/**
|
|
502
|
+
* @param ctx - the host context; `storage` and `multiRootScope` are injected.
|
|
503
|
+
* @param config - the patch row's `sharedStorageRoot`, `leasePath`, and `maxAdditionalRoots`.
|
|
497
504
|
*/
|
|
498
505
|
constructor(ctx, config = {}) {
|
|
499
506
|
super(ctx, "multiRootRegistry");
|
|
@@ -515,6 +522,10 @@ var MultiRootRegistry = class extends Service {
|
|
|
515
522
|
});
|
|
516
523
|
if (config.sharedStorageRoot !== void 0) this.ctx.multiRootScope.requireAdmission(this.operationProof);
|
|
517
524
|
this.ctx.multiRootScope.setRegistryAuthority(false);
|
|
525
|
+
if (this.sharedStorageRoot === void 0 || this.sharedStorageRoot.trim() === "") this.authorityState = {
|
|
526
|
+
kind: "config-invalid",
|
|
527
|
+
reason: `${DOMAIN_NAME}: sharedStorageRoot is required; the single-process registry mode was removed (ADR-0028)`
|
|
528
|
+
};
|
|
518
529
|
const configured = config.maxAdditionalRoots === void 0 ? 16 : config.maxAdditionalRoots;
|
|
519
530
|
if (Number.isInteger(configured) && configured >= 1 && configured <= 64) this.maxRoots = configured;
|
|
520
531
|
else {
|
|
@@ -555,7 +566,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
555
566
|
switch (this.authorityState.kind) {
|
|
556
567
|
case "active":
|
|
557
568
|
case "follower": return;
|
|
558
|
-
case "contended": return this.
|
|
569
|
+
case "contended": return this.connectionFailure !== void 0 ? `shared registry is unavailable: ${this.connectionFailure}` : REGISTRY_CONTENDED_MESSAGE;
|
|
559
570
|
case "storage-failed":
|
|
560
571
|
case "config-invalid": return this.authorityState.reason;
|
|
561
572
|
}
|
|
@@ -635,7 +646,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
635
646
|
* @param primaryRoot - the session workspace root (any spelling).
|
|
636
647
|
*/
|
|
637
648
|
overLimit(primaryRoot) {
|
|
638
|
-
return this.statusesOf(
|
|
649
|
+
return this.statusesOf(primaryKey(primaryRoot)).length > this.maxRoots;
|
|
639
650
|
}
|
|
640
651
|
/**
|
|
641
652
|
* Every registration of one primary root, in registry order, as last
|
|
@@ -646,7 +657,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
646
657
|
* @returns the statuses; empty when nothing is registered.
|
|
647
658
|
*/
|
|
648
659
|
list(primaryRoot) {
|
|
649
|
-
return this.statusesOf(
|
|
660
|
+
return this.statusesOf(primaryKey(primaryRoot));
|
|
650
661
|
}
|
|
651
662
|
/**
|
|
652
663
|
* Re-examine every registration of one primary root WITHOUT writing storage:
|
|
@@ -680,7 +691,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
680
691
|
if (this.client) return await this.remote("snapshot", [primaryRoot]);
|
|
681
692
|
}
|
|
682
693
|
if (this.authorityState.kind !== "active") return [];
|
|
683
|
-
const key =
|
|
694
|
+
const key = primaryKey(primaryRoot);
|
|
684
695
|
return await this.serialize(key, () => this.reclassify(key));
|
|
685
696
|
}
|
|
686
697
|
/**
|
|
@@ -692,16 +703,16 @@ var MultiRootRegistry = class extends Service {
|
|
|
692
703
|
if (this.disposed) throw new Error("multi-root registry: cannot admit an operation after disposal");
|
|
693
704
|
const capturedPolicy = structuredClone(policy);
|
|
694
705
|
await this.ensureAuthority();
|
|
695
|
-
const key =
|
|
696
|
-
if (this.
|
|
706
|
+
const key = primaryKey(capturedPolicy.workspaceRoot);
|
|
707
|
+
if (this.available) {
|
|
697
708
|
const snapshot = this.client ? await this.remoteSnapshot("admit", [key]) : await this.captureSnapshot(key);
|
|
698
|
-
const scope = freezeOperationScope(this.ctx.multiRootScope.resolveSnapshot(capturedPolicy, this.projectRoots(snapshot
|
|
709
|
+
const scope = freezeOperationScope(this.ctx.multiRootScope.resolveSnapshot(capturedPolicy, this.projectRoots(this.localSnapshotRoots(snapshot)), snapshot.available));
|
|
699
710
|
return await runRegistryOperation(scope, kind, snapshot.epoch, snapshot.revision, body, this.operationProof, capturedPolicy.mode);
|
|
700
711
|
}
|
|
701
712
|
const admission = await this.serialize(key, () => {
|
|
702
713
|
if (this.disposed) throw new Error("multi-root registry: cannot admit an operation after disposal");
|
|
703
714
|
return {
|
|
704
|
-
scope: freezeOperationScope(this.
|
|
715
|
+
scope: freezeOperationScope(this.ctx.multiRootScope.resolveSnapshot(capturedPolicy, this.projectRoots(this.cache.get(key) ?? []), false)),
|
|
705
716
|
epoch: this.operationEpoch,
|
|
706
717
|
revision: this.operationRevision
|
|
707
718
|
};
|
|
@@ -709,10 +720,113 @@ var MultiRootRegistry = class extends Service {
|
|
|
709
720
|
return await runRegistryOperation(admission.scope, kind, admission.epoch, admission.revision, body, this.operationProof, capturedPolicy.mode);
|
|
710
721
|
}
|
|
711
722
|
withPrimaryOperation(policy, body) {
|
|
712
|
-
const scope = this.ctx.multiRootScope.resolveSnapshot(policy, this.projectRoots(this.cache.get(
|
|
723
|
+
const scope = this.ctx.multiRootScope.resolveSnapshot(policy, this.projectRoots(this.cache.get(primaryKey(policy.workspaceRoot)) ?? []), false);
|
|
713
724
|
return runPrimaryOperation(freezeOperationScope(scope), policy.mode, this.operationProof, body);
|
|
714
725
|
}
|
|
715
726
|
/**
|
|
727
|
+
* The spellings one protected boundary contributes: the configured path,
|
|
728
|
+
* its current canonical resolution, and the canonical value pinned the
|
|
729
|
+
* first time it resolved — never re-pinned, so a later rename or symlink
|
|
730
|
+
* swap of the protected directory cannot drop the boundary the
|
|
731
|
+
* registration rules were enforced under. The list is deduplicated by
|
|
732
|
+
* {@link samePath}.
|
|
733
|
+
*/
|
|
734
|
+
boundarySpellings(kind, configured) {
|
|
735
|
+
const canonical = canonicalRoot(configured);
|
|
736
|
+
if (!this.pinnedProtectedPaths.has(kind)) this.pinnedProtectedPaths.set(kind, canonical);
|
|
737
|
+
const spellings = [];
|
|
738
|
+
for (const spelling of [
|
|
739
|
+
configured,
|
|
740
|
+
canonical,
|
|
741
|
+
this.pinnedProtectedPaths.get(kind)
|
|
742
|
+
]) if (!spellings.some((existing) => samePath(existing, spelling))) spellings.push(spelling);
|
|
743
|
+
return spellings;
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* The best-known protected-boundary set, plus whether it is COMPLETE.
|
|
747
|
+
*
|
|
748
|
+
* The set comes from trusted host configuration, never from a panel or
|
|
749
|
+
* shell claim: the scope row's `dshHome`, the physical medium
|
|
750
|
+
* `storeIdentity` bound, and the lease directory beside it.
|
|
751
|
+
* `complete` is false — and only NEW grants may then be refused — when a
|
|
752
|
+
* boundary cannot be proven: an invalid `dshHome` config, a configured
|
|
753
|
+
* home that is not a directory right now, or a medium that was never bound. Stored classification always consumes whatever IS known
|
|
754
|
+
* (pinned values included), so an unknown boundary never weakens the
|
|
755
|
+
* revalidation of existing records.
|
|
756
|
+
*/
|
|
757
|
+
protectedBoundarySet() {
|
|
758
|
+
const paths = [];
|
|
759
|
+
let complete = true;
|
|
760
|
+
const home = this.ctx.multiRootScope.dshHomeConfig;
|
|
761
|
+
switch (home.kind) {
|
|
762
|
+
case "absent": break;
|
|
763
|
+
case "invalid":
|
|
764
|
+
complete = false;
|
|
765
|
+
break;
|
|
766
|
+
case "configured": {
|
|
767
|
+
let isDirectory = false;
|
|
768
|
+
try {
|
|
769
|
+
isDirectory = statSync(home.path).isDirectory();
|
|
770
|
+
} catch {
|
|
771
|
+
isDirectory = false;
|
|
772
|
+
}
|
|
773
|
+
if (isDirectory) for (const spelling of this.boundarySpellings("dsh-home", home.path)) paths.push({
|
|
774
|
+
kind: "dsh-home",
|
|
775
|
+
path: spelling
|
|
776
|
+
});
|
|
777
|
+
else {
|
|
778
|
+
complete = false;
|
|
779
|
+
paths.push({
|
|
780
|
+
kind: "dsh-home",
|
|
781
|
+
path: home.path
|
|
782
|
+
});
|
|
783
|
+
const pinned = this.pinnedProtectedPaths.get("dsh-home");
|
|
784
|
+
if (pinned !== void 0 && !samePath(pinned, home.path)) paths.push({
|
|
785
|
+
kind: "dsh-home",
|
|
786
|
+
path: pinned
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (this.medium === void 0) complete = false;
|
|
793
|
+
else paths.push({
|
|
794
|
+
kind: "registry-medium",
|
|
795
|
+
path: this.medium.root
|
|
796
|
+
});
|
|
797
|
+
if (this.leasePath !== void 0) for (const spelling of this.boundarySpellings("registry-lease", dirname(this.leasePath))) paths.push({
|
|
798
|
+
kind: "registry-lease",
|
|
799
|
+
path: spelling
|
|
800
|
+
});
|
|
801
|
+
return {
|
|
802
|
+
paths,
|
|
803
|
+
complete
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* The protected DSH directories this Host can prove right now, or
|
|
808
|
+
* `undefined` when the set cannot be proven. `undefined` blocks every NEW
|
|
809
|
+
* grant; it never weakens the classification of stored records.
|
|
810
|
+
*/
|
|
811
|
+
protectedPaths() {
|
|
812
|
+
const { paths, complete } = this.protectedBoundarySet();
|
|
813
|
+
return complete ? paths : void 0;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Every protected entry this Host can prove — used wherever a partial set
|
|
817
|
+
* must still protect stored records and received snapshots.
|
|
818
|
+
*/
|
|
819
|
+
knownProtectedPaths() {
|
|
820
|
+
return this.protectedBoundarySet().paths;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* The one refusal shared by the owner mutation path and the follower
|
|
824
|
+
* pre-check: the protected set cannot be proven, so no new grant is safe.
|
|
825
|
+
*/
|
|
826
|
+
static protectedBoundaryUnknown() {
|
|
827
|
+
return new RootValidationError("protected-boundary-unknown", "the protected DSH directories cannot be resolved right now; no root can be registered until they can");
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
716
830
|
* Registers one additional root.
|
|
717
831
|
* @param primaryRoot - the session workspace root the root belongs to.
|
|
718
832
|
* @param input - the directory and optional alias.
|
|
@@ -721,12 +835,28 @@ var MultiRootRegistry = class extends Service {
|
|
|
721
835
|
*/
|
|
722
836
|
async add(primaryRoot, input) {
|
|
723
837
|
await this.ensureAuthority();
|
|
724
|
-
if (this.client)
|
|
838
|
+
if (this.client) {
|
|
839
|
+
const protectedPaths = this.protectedPaths();
|
|
840
|
+
if (protectedPaths === void 0) throw MultiRootRegistry.protectedBoundaryUnknown();
|
|
841
|
+
const expanded = expandRootInput(input.path);
|
|
842
|
+
if (process.platform === "win32" && isWindowsNetworkOrDevicePath(expanded)) throw new RootValidationError("unsupported-path", `Windows ACL confinement cannot cover network or device paths: ${expanded}`);
|
|
843
|
+
if (isAbsolute(expanded)) {
|
|
844
|
+
const candidate = canonicalRoot(expanded);
|
|
845
|
+
const conflict = protectedOverlap(candidate, protectedPaths);
|
|
846
|
+
if (conflict !== void 0) throw new RootValidationError("protected-path", `"${candidate}" overlaps the protected DSH directory "${conflict.path}" (${conflict.kind}) and cannot be registered`, {
|
|
847
|
+
conflict: conflict.path,
|
|
848
|
+
reference: candidate
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
return await this.remote("add", [primaryRoot, input]);
|
|
852
|
+
}
|
|
725
853
|
this.requireActive();
|
|
726
|
-
const key =
|
|
854
|
+
const key = primaryKey(primaryRoot);
|
|
727
855
|
return await this.serialize(key, async () => {
|
|
856
|
+
const protectedPaths = this.protectedPaths();
|
|
857
|
+
if (protectedPaths === void 0) throw MultiRootRegistry.protectedBoundaryUnknown();
|
|
728
858
|
const earlier = this.cache.get(key);
|
|
729
|
-
const statuses = this.reclassify(key);
|
|
859
|
+
const statuses = await this.reclassify(key);
|
|
730
860
|
const alias = normalizeAlias(input.alias);
|
|
731
861
|
const expanded = expandRootInput(input.path);
|
|
732
862
|
if (process.platform === "win32" && isWindowsNetworkOrDevicePath(expanded)) throw new RootValidationError("unsupported-path", `Windows ACL confinement cannot cover network or device paths: ${expanded}`);
|
|
@@ -737,9 +867,17 @@ var MultiRootRegistry = class extends Service {
|
|
|
737
867
|
const before = earlier?.find((candidate) => candidate.id === status.id);
|
|
738
868
|
return status.state !== "available" || before !== void 0 && before.state !== "available";
|
|
739
869
|
});
|
|
870
|
+
if (revived !== -1) {
|
|
871
|
+
const grant = singleGrantOf(statuses[revived]);
|
|
872
|
+
if (grant === void 0 || !samePath(preliminary, grant)) throw new RootValidationError("revive-target-changed", `the registration "${statuses[revived].path}" was granted for "${grant ?? "(unknown)"}" but now resolves to "${preliminary}"; remove it and add the new directory explicitly`, {
|
|
873
|
+
...grant === void 0 ? {} : { conflict: grant },
|
|
874
|
+
reference: preliminary
|
|
875
|
+
});
|
|
876
|
+
}
|
|
740
877
|
if (revived === -1 && statuses.length >= this.maxRoots) throw new RootValidationError("root-limit-reached", `this workspace already has ${statuses.length} additional roots; the configured limit is ${this.maxRoots}. Remove one first, or raise maxAdditionalRoots.`, { reference: String(this.maxRoots) });
|
|
741
878
|
const canonical = validateRootCandidate(input.path, {
|
|
742
879
|
primaryRoot: key,
|
|
880
|
+
protectedPaths,
|
|
743
881
|
existing: statuses.flatMap((status, index) => {
|
|
744
882
|
if (index === revived) return [];
|
|
745
883
|
const boundary = reservedRootBoundary(status);
|
|
@@ -798,9 +936,9 @@ var MultiRootRegistry = class extends Service {
|
|
|
798
936
|
access
|
|
799
937
|
]);
|
|
800
938
|
this.requireActive();
|
|
801
|
-
const key =
|
|
939
|
+
const key = primaryKey(primaryRoot);
|
|
802
940
|
return await this.serialize(key, async () => {
|
|
803
|
-
const statuses = this.reclassify(key);
|
|
941
|
+
const statuses = await this.reclassify(key);
|
|
804
942
|
const targetIndex = resolveRootIndex(statuses, ref);
|
|
805
943
|
const target = statuses[targetIndex];
|
|
806
944
|
if (target.access === access) return statuses;
|
|
@@ -840,8 +978,8 @@ var MultiRootRegistry = class extends Service {
|
|
|
840
978
|
await this.ensureAuthority();
|
|
841
979
|
if (this.client) return await this.remote("removeAt", [primaryRoot, ref]);
|
|
842
980
|
this.requireActive();
|
|
843
|
-
const key =
|
|
844
|
-
return await this.serialize(key, async () => await this.persist(key, removeStatusAt(this.reclassify(key), ref)));
|
|
981
|
+
const key = primaryKey(primaryRoot);
|
|
982
|
+
return await this.serialize(key, async () => await this.persist(key, removeStatusAt(await this.reclassify(key), ref)));
|
|
845
983
|
}
|
|
846
984
|
/**
|
|
847
985
|
* Set or clear one registration's display alias.
|
|
@@ -859,9 +997,9 @@ var MultiRootRegistry = class extends Service {
|
|
|
859
997
|
alias ?? null
|
|
860
998
|
]);
|
|
861
999
|
this.requireActive();
|
|
862
|
-
const key =
|
|
1000
|
+
const key = primaryKey(primaryRoot);
|
|
863
1001
|
return await this.serialize(key, async () => {
|
|
864
|
-
const statuses = this.reclassify(key);
|
|
1002
|
+
const statuses = await this.reclassify(key);
|
|
865
1003
|
const targetIndex = resolveRootIndex(statuses, ref);
|
|
866
1004
|
const normalized = normalizeAlias(alias);
|
|
867
1005
|
const next = statuses.map((status, index) => {
|
|
@@ -898,9 +1036,9 @@ var MultiRootRegistry = class extends Service {
|
|
|
898
1036
|
async setSkillsMetadata(primaryRoot, ref, patch) {
|
|
899
1037
|
await this.ensureAuthority();
|
|
900
1038
|
this.requireActive();
|
|
901
|
-
const key =
|
|
1039
|
+
const key = primaryKey(primaryRoot);
|
|
902
1040
|
return await this.serialize(key, async () => {
|
|
903
|
-
const statuses = this.reclassify(key);
|
|
1041
|
+
const statuses = await this.reclassify(key);
|
|
904
1042
|
const target = resolveRootIndex(statuses, ref);
|
|
905
1043
|
if (patch.aliasId !== void 0) validateAliasId(patch.aliasId, statuses.filter((_row, index) => index !== target));
|
|
906
1044
|
return await this.persist(key, statuses.map((row, index) => index === target ? {
|
|
@@ -925,9 +1063,9 @@ var MultiRootRegistry = class extends Service {
|
|
|
925
1063
|
beforeRef ?? null
|
|
926
1064
|
]);
|
|
927
1065
|
this.requireActive();
|
|
928
|
-
const key =
|
|
1066
|
+
const key = primaryKey(primaryRoot);
|
|
929
1067
|
return await this.serialize(key, async () => {
|
|
930
|
-
const statuses = this.reclassify(key);
|
|
1068
|
+
const statuses = await this.reclassify(key);
|
|
931
1069
|
const targetIndex = resolveRootIndex(statuses, ref);
|
|
932
1070
|
const anchorIndex = beforeRef === void 0 ? void 0 : resolveRootIndex(statuses, beforeRef);
|
|
933
1071
|
if (anchorIndex === targetIndex) return statuses;
|
|
@@ -954,12 +1092,12 @@ var MultiRootRegistry = class extends Service {
|
|
|
954
1092
|
await this.ensureAuthority();
|
|
955
1093
|
if (this.client) return await this.remote("recheck", [primaryRoot]);
|
|
956
1094
|
this.requireActive();
|
|
957
|
-
const key =
|
|
958
|
-
return await this.serialize(key, async () => await this.persist(key, this.reclassify(key)));
|
|
1095
|
+
const key = primaryKey(primaryRoot);
|
|
1096
|
+
return await this.serialize(key, async () => await this.persist(key, await this.reclassify(key)));
|
|
959
1097
|
}
|
|
960
1098
|
/**
|
|
961
1099
|
* Observe registry changes.
|
|
962
|
-
* @param listener - called with the
|
|
1100
|
+
* @param listener - called with the Registry key (`primaryKey()`, case-folded on Windows) after each durable change.
|
|
963
1101
|
* @returns the disposer that stops observing.
|
|
964
1102
|
*/
|
|
965
1103
|
onChange(listener) {
|
|
@@ -974,10 +1112,10 @@ var MultiRootRegistry = class extends Service {
|
|
|
974
1112
|
* @returns the canonical paths of every `available` root.
|
|
975
1113
|
*/
|
|
976
1114
|
granted(primaryRoot) {
|
|
977
|
-
return this.
|
|
1115
|
+
return this.ctx.multiRootScope.snapshot({
|
|
978
1116
|
workspaceRoot: primaryRoot,
|
|
979
1117
|
mode: "workspace-write"
|
|
980
|
-
}).additionalRoots
|
|
1118
|
+
}).additionalRoots;
|
|
981
1119
|
}
|
|
982
1120
|
/**
|
|
983
1121
|
* The scope the registry publishes: only usable roots, in registry order.
|
|
@@ -988,8 +1126,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
988
1126
|
return this.granted(policy.workspaceRoot);
|
|
989
1127
|
}
|
|
990
1128
|
/** Classify one stored record set and cache it. */
|
|
991
|
-
accept(
|
|
992
|
-
const key = canonicalRoot(primaryRoot);
|
|
1129
|
+
accept(key, record) {
|
|
993
1130
|
const statuses = this.classify(key, record);
|
|
994
1131
|
this.cache.set(key, statuses);
|
|
995
1132
|
this.publish(key, statuses);
|
|
@@ -1001,7 +1138,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1001
1138
|
* staging uses it so a half-opened domain cannot materialize rows.
|
|
1002
1139
|
*/
|
|
1003
1140
|
classify(key, record) {
|
|
1004
|
-
const statuses = classifyStoredRoots(key, record.roots.map(toRegisteredRoot));
|
|
1141
|
+
const statuses = classifyStoredRoots(canonicalRoot(key), record.roots.map(toRegisteredRoot), process.platform, this.knownProtectedPaths());
|
|
1005
1142
|
if (statuses.length > this.maxRoots && !this.warnedOverLimit.has(key)) {
|
|
1006
1143
|
this.warnedOverLimit.add(key);
|
|
1007
1144
|
this.ctx.logger.warn(`multi-root-workspace: ${statuses.length} roots are stored for ${key}, above the configured limit of ${this.maxRoots}; all of them stay granted, only new adds are refused`);
|
|
@@ -1017,20 +1154,38 @@ var MultiRootRegistry = class extends Service {
|
|
|
1017
1154
|
statusesOf(key) {
|
|
1018
1155
|
const cached = this.cache.get(key);
|
|
1019
1156
|
if (cached !== void 0) return cached;
|
|
1020
|
-
const
|
|
1021
|
-
if (
|
|
1022
|
-
return this.accept(key, record);
|
|
1157
|
+
const found = this.lookupRecords(key);
|
|
1158
|
+
if (found === void 0) return [];
|
|
1159
|
+
return this.accept(key, found.record);
|
|
1023
1160
|
}
|
|
1024
1161
|
/**
|
|
1025
|
-
* The stored record set of one key,
|
|
1026
|
-
*
|
|
1027
|
-
*
|
|
1028
|
-
* the
|
|
1162
|
+
* The stored record set of one key: `{ record, migrated: false }` when the
|
|
1163
|
+
* spelling key holds it; `{ record, migrated: true }` when only the legacy
|
|
1164
|
+
* CANONICAL key does — stores written before the upstream primary spelling
|
|
1165
|
+
* became the key (v0.1.14 and earlier). The fallback follows the CURRENT
|
|
1166
|
+
* resolution ONLY for such a not-yet-migrated store; the first serialized
|
|
1167
|
+
* access copies the record forward under the spelling key (see
|
|
1168
|
+
* {@link reclassify}), after which resolution can never re-key a grant.
|
|
1169
|
+
* `undefined` when there is no record (or when the store itself could not
|
|
1170
|
+
* be read: an unusable store reads as "nothing registered" so reads stay
|
|
1171
|
+
* answerable and the surfaces can explain the situation, while every write
|
|
1172
|
+
* fails loudly in `requireTable()`).
|
|
1029
1173
|
*/
|
|
1030
1174
|
lookupRecords(key) {
|
|
1031
1175
|
if (this.authorityState.kind !== "active") return void 0;
|
|
1032
1176
|
try {
|
|
1033
|
-
|
|
1177
|
+
const record = this.table?.get(key);
|
|
1178
|
+
if (record !== void 0) return {
|
|
1179
|
+
record,
|
|
1180
|
+
migrated: false
|
|
1181
|
+
};
|
|
1182
|
+
const legacy = canonicalRoot(key);
|
|
1183
|
+
if (legacy === key) return void 0;
|
|
1184
|
+
const migrated = this.table?.get(legacy);
|
|
1185
|
+
return migrated === void 0 ? void 0 : {
|
|
1186
|
+
record: migrated,
|
|
1187
|
+
migrated: true
|
|
1188
|
+
};
|
|
1034
1189
|
} catch (error) {
|
|
1035
1190
|
if (unknownStorageState(error)) this.enterStorageFailed("registry storage state cannot be confirmed; restart and reconcile", "quarantine");
|
|
1036
1191
|
throw error;
|
|
@@ -1042,14 +1197,20 @@ var MultiRootRegistry = class extends Service {
|
|
|
1042
1197
|
* directory. Updates the cache, republishes the scope, and returns the new
|
|
1043
1198
|
* list — the shared body of the read-path re-checks.
|
|
1044
1199
|
*/
|
|
1045
|
-
reclassify(key) {
|
|
1046
|
-
const
|
|
1047
|
-
if (
|
|
1200
|
+
async reclassify(key) {
|
|
1201
|
+
const found = this.lookupRecords(key);
|
|
1202
|
+
if (found === void 0) {
|
|
1048
1203
|
this.cache.set(key, []);
|
|
1049
1204
|
this.publish(key, []);
|
|
1050
1205
|
return [];
|
|
1051
1206
|
}
|
|
1052
|
-
|
|
1207
|
+
if (found.migrated) try {
|
|
1208
|
+
await this.requireTable().put(key, found.record);
|
|
1209
|
+
} catch (error) {
|
|
1210
|
+
if (unknownStorageState(error)) this.enterStorageFailed("registry write result is unknown; restart and reconcile durable state", "quarantine");
|
|
1211
|
+
throw error;
|
|
1212
|
+
}
|
|
1213
|
+
return this.accept(key, found.record);
|
|
1053
1214
|
}
|
|
1054
1215
|
/**
|
|
1055
1216
|
* Persist one status list, then republish it into the scope and to listeners.
|
|
@@ -1060,13 +1221,12 @@ var MultiRootRegistry = class extends Service {
|
|
|
1060
1221
|
const table = this.requireTable();
|
|
1061
1222
|
const durable = persistedPrimaryRoot.parse({ roots: migrateRootSkills(statuses.map(toPersistedRoot)) });
|
|
1062
1223
|
try {
|
|
1063
|
-
|
|
1064
|
-
else await table.put(key, durable);
|
|
1224
|
+
await table.put(key, durable);
|
|
1065
1225
|
} catch (error) {
|
|
1066
1226
|
if (unknownStorageState(error)) this.enterStorageFailed("registry write result is unknown; restart and reconcile durable state", "quarantine");
|
|
1067
1227
|
throw error;
|
|
1068
1228
|
}
|
|
1069
|
-
const classified = statuses.length === 0 ? [] : classifyStoredRoots(key, durable.roots.map(toRegisteredRoot));
|
|
1229
|
+
const classified = statuses.length === 0 ? [] : classifyStoredRoots(canonicalRoot(key), durable.roots.map(toRegisteredRoot), process.platform, this.knownProtectedPaths());
|
|
1070
1230
|
this.cache.set(key, classified);
|
|
1071
1231
|
this.publish(key, classified);
|
|
1072
1232
|
return classified;
|
|
@@ -1112,12 +1272,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1112
1272
|
const withheld = statuses.filter((status) => status.state !== "available");
|
|
1113
1273
|
const signature = [...statuses.filter((status) => status.state === "available").map((status) => `available:${status.access}:${recordedGrantOf(status)}`), ...withheld.map((status) => `${status.state}:${status.invalidReason ?? ""}:${status.access}:${status.path}:${recordedGrantOf(status) ?? ""}`)].join("\n");
|
|
1114
1274
|
const previousMetadata = this.metadataPublished.get(key);
|
|
1115
|
-
const metadata = JSON.stringify(
|
|
1116
|
-
row.id,
|
|
1117
|
-
row.aliasId,
|
|
1118
|
-
row.skillsEnabled,
|
|
1119
|
-
row.state
|
|
1120
|
-
]));
|
|
1275
|
+
const metadata = JSON.stringify(statuses);
|
|
1121
1276
|
this.metadataPublished.set(key, metadata);
|
|
1122
1277
|
if ((this.published.get(key) ?? "") === signature) {
|
|
1123
1278
|
if (previousMetadata !== metadata && (previousMetadata !== void 0 || statuses.length > 0)) {
|
|
@@ -1137,7 +1292,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1137
1292
|
projectRoots(statuses) {
|
|
1138
1293
|
return statuses.flatMap((status) => {
|
|
1139
1294
|
const recorded = recordedGrantOf(status);
|
|
1140
|
-
if (status.state === "invalid" && status.invalidReason
|
|
1295
|
+
if (status.state === "invalid" && status.invalidReason === void 0 || recorded === void 0) return [];
|
|
1141
1296
|
return [{
|
|
1142
1297
|
id: status.id,
|
|
1143
1298
|
path: status.path,
|
|
@@ -1160,10 +1315,10 @@ var MultiRootRegistry = class extends Service {
|
|
|
1160
1315
|
});
|
|
1161
1316
|
}
|
|
1162
1317
|
async captureSnapshot(primary) {
|
|
1163
|
-
const key =
|
|
1164
|
-
return await this.serialize(key, () => {
|
|
1318
|
+
const key = primaryKey(primary);
|
|
1319
|
+
return await this.serialize(key, async () => {
|
|
1165
1320
|
this.requireActive();
|
|
1166
|
-
this.reclassify(key);
|
|
1321
|
+
await this.reclassify(key);
|
|
1167
1322
|
return this.snapshotOf(key);
|
|
1168
1323
|
});
|
|
1169
1324
|
}
|
|
@@ -1205,15 +1360,19 @@ var MultiRootRegistry = class extends Service {
|
|
|
1205
1360
|
this.notifyShared(key);
|
|
1206
1361
|
for (const listener of this.listeners) listener(key);
|
|
1207
1362
|
}
|
|
1363
|
+
/** Narrow owner rows for this Host, identically for projection and admission. */
|
|
1364
|
+
localSnapshotRoots(snapshot) {
|
|
1365
|
+
return markProtectedPaths(snapshot.roots.map((row) => Object.fromEntries(Object.entries({
|
|
1366
|
+
...row,
|
|
1367
|
+
id: additionalRootId(row.id)
|
|
1368
|
+
}).filter(([, value]) => value !== void 0))), this.knownProtectedPaths());
|
|
1369
|
+
}
|
|
1208
1370
|
applySnapshot(snapshot) {
|
|
1209
1371
|
if (!this.client || snapshot.store !== this.medium?.id || snapshot.epoch !== this.client.epoch) return;
|
|
1210
1372
|
const previous = this.remoteRevisions.get(snapshot.primary) ?? -1;
|
|
1211
1373
|
if (snapshot.revision < previous) return;
|
|
1212
1374
|
this.remoteRevisions.set(snapshot.primary, snapshot.revision);
|
|
1213
|
-
const rows =
|
|
1214
|
-
...row,
|
|
1215
|
-
id: additionalRootId(row.id)
|
|
1216
|
-
}).filter(([, value]) => value !== void 0)));
|
|
1375
|
+
const rows = this.localSnapshotRoots(snapshot);
|
|
1217
1376
|
this.commit(() => {
|
|
1218
1377
|
this.cache.set(snapshot.primary, rows);
|
|
1219
1378
|
this.publish(snapshot.primary, rows);
|
|
@@ -1283,7 +1442,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1283
1442
|
client.close();
|
|
1284
1443
|
throw error;
|
|
1285
1444
|
}
|
|
1286
|
-
if (generation !== this.connectionGeneration || client !== this.client || snapshot.store !== this.medium?.id || snapshot.epoch !== client.epoch || snapshot.primary !==
|
|
1445
|
+
if (generation !== this.connectionGeneration || client !== this.client || snapshot.store !== this.medium?.id || snapshot.epoch !== client.epoch || snapshot.primary !== primaryKey(String(args[0]))) {
|
|
1287
1446
|
client.close();
|
|
1288
1447
|
throw new Error("stale registry connection or authority epoch");
|
|
1289
1448
|
}
|
|
@@ -1379,7 +1538,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1379
1538
|
this.enterStorageFailed(`${DOMAIN_NAME}: leasePath must be an absolute path`, "config");
|
|
1380
1539
|
return;
|
|
1381
1540
|
}
|
|
1382
|
-
if (this.
|
|
1541
|
+
if (this.medium === void 0) try {
|
|
1383
1542
|
if (!isAbsolute(this.sharedStorageRoot)) throw new SharedConfigError("sharedStorageRoot must be absolute");
|
|
1384
1543
|
const medium = storeIdentity(this.sharedStorageRoot);
|
|
1385
1544
|
if (storeIdentity(dirname(leasePath)).id !== medium.id || basename(leasePath) !== `multi_root_workspace.lock`) throw new SharedConfigError("shared registry requires its canonical medium lock, without alternate lock names");
|
|
@@ -1454,7 +1613,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1454
1613
|
async openDomain() {
|
|
1455
1614
|
let domain;
|
|
1456
1615
|
try {
|
|
1457
|
-
domain =
|
|
1616
|
+
domain = await openAuthorityStorage(this.authorityStorageContext, this.medium.root, multiRootDomainSpec);
|
|
1458
1617
|
} catch (error) {
|
|
1459
1618
|
const reason = `${DOMAIN_NAME}: ${error instanceof Error ? error.message : String(error)}`;
|
|
1460
1619
|
if (this.lastOpenFailure !== reason) {
|
|
@@ -1483,7 +1642,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1483
1642
|
}
|
|
1484
1643
|
this.ctx.logger.warn(`multi-root skills: metadata migration failed; Skills remain withheld: ${String(error)}`);
|
|
1485
1644
|
}
|
|
1486
|
-
const key =
|
|
1645
|
+
const key = primaryKey(primaryRoot);
|
|
1487
1646
|
staged.set(key, this.classify(key, accepted));
|
|
1488
1647
|
}
|
|
1489
1648
|
} catch (error) {
|
|
@@ -1524,8 +1683,7 @@ var MultiRootRegistry = class extends Service {
|
|
|
1524
1683
|
/** Fail closed: empty scope, no table, contended state. */
|
|
1525
1684
|
enterContended() {
|
|
1526
1685
|
this.operationEpoch = void 0;
|
|
1527
|
-
|
|
1528
|
-
else this.withdrawPublished();
|
|
1686
|
+
this.remoteUnavailable();
|
|
1529
1687
|
this.ctx.multiRootScope.setRegistryAuthority(false);
|
|
1530
1688
|
this.table = void 0;
|
|
1531
1689
|
this.authorityState = { kind: "contended" };
|
|
@@ -1538,11 +1696,9 @@ var MultiRootRegistry = class extends Service {
|
|
|
1538
1696
|
enterStorageFailed(reason, recovery) {
|
|
1539
1697
|
this.operationEpoch = void 0;
|
|
1540
1698
|
this.ctx.multiRootScope.setRegistryAuthority(false);
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
this.server = void 0;
|
|
1545
|
-
} else this.withdrawPublished();
|
|
1699
|
+
for (const [key, rows] of this.cache) this.withholdScope(key, rows);
|
|
1700
|
+
this.server?.close();
|
|
1701
|
+
this.server = void 0;
|
|
1546
1702
|
this.table = void 0;
|
|
1547
1703
|
this.authorityState = {
|
|
1548
1704
|
kind: "storage-failed",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { c as loadHostKoffi } from "./protocol-CwDnFEyK.js";
|
|
1
2
|
import { realpathSync } from "node:fs";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import { basename, dirname, join, resolve } from "node:path";
|
|
@@ -23,7 +24,7 @@ let bindings;
|
|
|
23
24
|
/** Load kernel32 through Koffi the first time a Windows process needs it. */
|
|
24
25
|
async function kernel32() {
|
|
25
26
|
if (bindings !== void 0) return bindings;
|
|
26
|
-
const library = (await
|
|
27
|
+
const library = (await loadHostKoffi()).load("kernel32.dll");
|
|
27
28
|
bindings = {
|
|
28
29
|
createSemaphoreW: library.func("__stdcall", "CreateSemaphoreW", "intptr", [
|
|
29
30
|
"void*",
|
package/lib/registry.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as MultiRootRegistry, c as multiRootDomainSpec, i as MAX_ALIAS_LENGTH, n as DOMAIN_NAME, o as REGISTRY_CONTENDED_MESSAGE, r as MAX_ADDITIONAL_ROOTS_CEILING, s as TABLE_NAME, t as DEFAULT_MAX_ADDITIONAL_ROOTS } from "./registry-
|
|
2
|
-
import { o as nativeHostAvailability } from "./protocol-
|
|
1
|
+
import { a as MultiRootRegistry, c as multiRootDomainSpec, i as MAX_ALIAS_LENGTH, n as DOMAIN_NAME, o as REGISTRY_CONTENDED_MESSAGE, r as MAX_ADDITIONAL_ROOTS_CEILING, s as TABLE_NAME, t as DEFAULT_MAX_ADDITIONAL_ROOTS } from "./registry-DyDNDSJZ.js";
|
|
2
|
+
import { o as nativeHostAvailability } from "./protocol-CwDnFEyK.js";
|
|
3
3
|
export { DEFAULT_MAX_ADDITIONAL_ROOTS, DOMAIN_NAME, MAX_ADDITIONAL_ROOTS_CEILING, MAX_ALIAS_LENGTH, MultiRootRegistry, MultiRootRegistry as default, REGISTRY_CONTENDED_MESSAGE, TABLE_NAME, multiRootDomainSpec, nativeHostAvailability };
|