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.
- package/package.json +1 -1
- package/src/capabilities/apply-engine.js +20 -4
- package/src/capabilities/lifecycle-feed.js +47 -0
- package/src/capabilities/mcp-drain.js +6 -0
- package/src/capabilities/mcp-facade-plugin.js +14 -4
- package/src/capabilities/mcp-facade.js +1 -1
- package/src/capabilities/mcp-inventory.js +152 -0
- package/src/capabilities/mcp-manager.js +220 -171
- package/src/capabilities/mcp-mount-ownership.js +114 -0
- package/src/capabilities/mcp-mount.js +334 -82
- package/src/capabilities/mcp-operation-coordinator.js +76 -0
- package/src/capabilities/mcp-runtime.js +3 -29
- package/src/capabilities/skill-selection-plugin.js +8 -0
- package/src/file-lease/client.js +61 -3
- package/src/file-lease/negotiation.js +89 -0
- package/src/file-lease/plugin.js +25 -23
- package/src/file-lease/tools.js +71 -121
- package/src/file-lease/watch.js +225 -36
|
@@ -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()
|