weir-harness 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,114 @@
1
+ // Internal, module-realm Mount Attempt Ownership. Logical identity, the actual
2
+ // Loader group and the opaque owner are deliberately separate facts. Nothing in
3
+ // this module is part of a public receipt or persisted selection payload.
4
+ import { randomUUID } from 'node:crypto'
5
+
6
+ export const MCP_GROUP_PREFIX = 'weir-mcp-'
7
+ const ACTUAL_OWNER_SEPARATOR = '~'
8
+
9
+ export function isMcpResidueId(id) {
10
+ return typeof id === 'string' && id.startsWith(MCP_GROUP_PREFIX) && !id.endsWith('-facade') && !id.endsWith('-client')
11
+ }
12
+
13
+ export function isSuffixedMcpGroupId(id) {
14
+ return typeof id === 'string' && id.startsWith(MCP_GROUP_PREFIX) && id.includes(ACTUAL_OWNER_SEPARATOR, MCP_GROUP_PREFIX.length)
15
+ }
16
+
17
+ /** Resolve only the explicit facade child config carried by a real group row. */
18
+ export function mcpFacadeIdentity(row, groupId = row?.options?.id ?? row?.id) {
19
+ const options = row?.options ?? row
20
+ const config = Array.isArray(options?.config) ? options.config : []
21
+ for (const child of config) {
22
+ if (child?.name !== 'weir-harness/mcp-facade-plugin') continue
23
+ const facade = child.config
24
+ if (typeof facade?.identity !== 'string' || facade.identity.length === 0) continue
25
+ if (facade.group !== groupId) continue
26
+ return facade.identity
27
+ }
28
+ return null
29
+ }
30
+
31
+ /**
32
+ * Resolve one actual group without reverse-parsing generated suffixes. The
33
+ * precedence is part of the inventory/recovery contract: own exact mount, live
34
+ * module-realm allocation, explicit facade config, then a true legacy ID only.
35
+ * @param {{ groupId: string, mounted?: Map<string, any>, ownership?: any, row?: any }} input
36
+ */
37
+ export function resolveMcpGroupIdentity({ groupId, mounted = new Map(), ownership = null, row = null }) {
38
+ for (const [identity, mount] of mounted) {
39
+ if (mount?.groupId === groupId) return { identity, source: 'own-mounted', mount, allocation: ownership?.forGroup(groupId) ?? null }
40
+ }
41
+ const allocation = ownership?.forGroup(groupId) ?? null
42
+ if (allocation) return { identity: allocation.identity, source: 'live-allocation', mount: null, allocation }
43
+ const configured = mcpFacadeIdentity(row, groupId)
44
+ if (configured !== null) return { identity: configured, source: 'facade-config', mount: null, allocation: null }
45
+ if (!isMcpResidueId(groupId) || isSuffixedMcpGroupId(groupId)) return null
46
+ return { identity: groupId.slice(MCP_GROUP_PREFIX.length), source: 'legacy', mount: null, allocation: null }
47
+ }
48
+
49
+ /**
50
+ * A fresh registry is useful for isolated component tests. Production managers
51
+ * share mcpMountOwnership below, which is necessarily scoped to this loaded
52
+ * bundle module instance; another module realm is never guessed to be owned.
53
+ */
54
+ export function createMcpMountOwnership() {
55
+ const byGroup = new Map()
56
+ let sequence = 0
57
+
58
+ /** @param {string} identity @param {{ holder?: any, tree?: any, available?: (groupId: string) => boolean }} options */
59
+ function claim(identity, { holder, tree = null, available = () => true } = {}) {
60
+ const legacy = `${MCP_GROUP_PREFIX}${identity}`
61
+ let groupId = legacy
62
+ while (byGroup.has(groupId) || available(groupId) !== true) {
63
+ sequence += 1
64
+ groupId = `${legacy}${ACTUAL_OWNER_SEPARATOR}${sequence.toString(36)}-${randomUUID().replaceAll('-', '')}`
65
+ }
66
+ const record = {
67
+ identity, groupId, owner: randomUUID(), holder, tree,
68
+ state: 'claimed', pending: new Set(),
69
+ }
70
+ // Check-and-claim are synchronous: no other mount attempt can interleave
71
+ // between the availability checks and this exact group becoming occupied.
72
+ byGroup.set(groupId, record)
73
+ return record
74
+ }
75
+
76
+ /** Claim only known residue for disposal; this never authorizes group reuse. */
77
+ function claimResidue({ identity, groupId, holder, tree = null }) {
78
+ const current = byGroup.get(groupId)
79
+ if (current) return current.holder === holder && current.identity === identity ? current : null
80
+ if (!isMcpResidueId(groupId)) return null
81
+ const record = {
82
+ identity, groupId, owner: randomUUID(), holder, tree,
83
+ state: 'residue', pending: new Set(),
84
+ }
85
+ byGroup.set(groupId, record)
86
+ return record
87
+ }
88
+
89
+ function transition(record, state) {
90
+ if (!record || byGroup.get(record.groupId) !== record) return false
91
+ record.state = state
92
+ return true
93
+ }
94
+
95
+ /** Release is compare-exact, idempotent, and impossible while work is pending. */
96
+ function release(record, { provenAbsent = false, owner = record?.owner } = {}) {
97
+ if (!record || provenAbsent !== true || record.pending.size > 0) return false
98
+ if (record.owner !== owner || byGroup.get(record.groupId) !== record) return false
99
+ byGroup.delete(record.groupId)
100
+ record.state = 'released'
101
+ return true
102
+ }
103
+
104
+ return {
105
+ claim,
106
+ claimResidue,
107
+ transition,
108
+ release,
109
+ forGroup: groupId => byGroup.get(groupId) ?? null,
110
+ records: () => [...byGroup.values()],
111
+ }
112
+ }
113
+
114
+ export const mcpMountOwnership = createMcpMountOwnership()