amalgm 0.1.245 → 0.1.246
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/README.md +12 -0
- package/lib/cli.js +146 -8
- package/lib/layout.js +89 -4
- package/lib/shared-realtime-tunnel.js +384 -43
- package/lib/supervisor.js +0 -3
- package/package.json +2 -2
- package/runtime/scripts/amalgm-mcp/adapters/contract.js +197 -0
- package/runtime/scripts/amalgm-mcp/adapters/filesystem.js +135 -0
- package/runtime/scripts/amalgm-mcp/adapters/git.js +84 -0
- package/runtime/scripts/amalgm-mcp/adapters/index.js +43 -0
- package/runtime/scripts/amalgm-mcp/adapters/reference.js +31 -0
- package/runtime/scripts/amalgm-mcp/adapters/truth.js +19 -0
- package/runtime/scripts/amalgm-mcp/browser/cookie-jar.js +20 -68
- package/runtime/scripts/amalgm-mcp/index.js +4 -0
- package/runtime/scripts/amalgm-mcp/lib/layout.js +89 -4
- package/runtime/scripts/amalgm-mcp/observer/README.md +259 -0
- package/runtime/scripts/amalgm-mcp/observer/apply.js +150 -0
- package/runtime/scripts/amalgm-mcp/observer/continuity.js +111 -0
- package/runtime/scripts/amalgm-mcp/observer/edges.js +111 -0
- package/runtime/scripts/amalgm-mcp/observer/index.js +1146 -0
- package/runtime/scripts/amalgm-mcp/observer/scan.js +387 -0
- package/runtime/scripts/amalgm-mcp/observer/store.js +262 -0
- package/runtime/scripts/amalgm-mcp/observer/verify.js +200 -0
- package/runtime/scripts/amalgm-mcp/observer/watch.js +62 -0
- package/runtime/scripts/amalgm-mcp/project-context/store.js +19 -87
- package/runtime/scripts/amalgm-mcp/registration/classify.js +33 -0
- package/runtime/scripts/amalgm-mcp/registration/entity-cloud.js +456 -0
- package/runtime/scripts/amalgm-mcp/registration/entity-content.js +345 -0
- package/runtime/scripts/amalgm-mcp/registration/index.js +752 -0
- package/runtime/scripts/amalgm-mcp/registration/refusal.js +42 -0
- package/runtime/scripts/amalgm-mcp/registration/repo-followers.js +127 -0
- package/runtime/scripts/amalgm-mcp/registration/repo-states.js +109 -0
- package/runtime/scripts/amalgm-mcp/registration/service.js +310 -0
- package/runtime/scripts/amalgm-mcp/registration/tree.js +178 -0
- package/runtime/scripts/amalgm-mcp/registry/evidence.js +826 -0
- package/runtime/scripts/amalgm-mcp/registry/index.js +666 -0
- package/runtime/scripts/amalgm-mcp/registry/store.js +290 -0
- package/runtime/scripts/amalgm-mcp/repocard/README.md +103 -0
- package/runtime/scripts/amalgm-mcp/repocard/apply.js +111 -0
- package/runtime/scripts/amalgm-mcp/repocard/capture-worker.js +94 -0
- package/runtime/scripts/amalgm-mcp/repocard/capture.js +149 -0
- package/runtime/scripts/amalgm-mcp/repocard/follow.js +310 -0
- package/runtime/scripts/amalgm-mcp/repocard/git.js +48 -0
- package/runtime/scripts/amalgm-mcp/repocard/index.js +48 -0
- package/runtime/scripts/amalgm-mcp/server/local-service-router.js +2 -0
- package/runtime/scripts/amalgm-mcp/server/routes/entities.js +287 -0
- package/runtime/scripts/amalgm-mcp/server/routes/state.js +0 -13
- package/runtime/scripts/amalgm-mcp/state/attachments.js +11 -45
- package/runtime/scripts/amalgm-mcp/state/db.js +46 -215
- package/runtime/scripts/amalgm-mcp/state/docs.js +301 -1101
- package/runtime/scripts/amalgm-mcp/state/mutation-contracts.js +0 -99
- package/runtime/scripts/amalgm-mcp/state/mutations.js +130 -507
- package/runtime/scripts/amalgm-mcp/state/promotions.js +1 -21
- package/runtime/scripts/amalgm-mcp/state/replicas.js +13 -134
- package/runtime/scripts/amalgm-mcp/state/shared-rest.js +3 -46
- package/runtime/scripts/amalgm-mcp/tests/adapters.test.js +379 -0
- package/runtime/scripts/amalgm-mcp/tests/browser-cookie-cloud.test.js +0 -193
- package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.life.test.js +449 -0
- package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.rig.js +107 -0
- package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.watch.test.js +213 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/adapter.js +72 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/assert.js +497 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/bind.js +91 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/graph.js +1031 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/ledger.js +234 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/referee.js +118 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.oracle.test.js +1365 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.registry.test.js +967 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.rig.js +239 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.storm.test.js +486 -0
- package/runtime/scripts/amalgm-mcp/tests/fake-watch.js +35 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.links.test.js +289 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.rig.js +103 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.roots.test.js +505 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.storm.test.js +389 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.territory.test.js +845 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.test.js +657 -0
- package/runtime/scripts/amalgm-mcp/tests/project-context.test.js +17 -32
- package/runtime/scripts/amalgm-mcp/tests/registration.service.test.js +256 -0
- package/runtime/scripts/amalgm-mcp/tests/registration.test.js +931 -0
- package/runtime/scripts/amalgm-mcp/tests/repocard.storm.test.js +284 -0
- package/runtime/scripts/amalgm-mcp/tests/repocard.test.js +371 -0
- package/runtime/scripts/amalgm-mcp/tests/repofollow.storm.test.js +435 -0
- package/runtime/scripts/amalgm-mcp/tests/repofollow.test.js +675 -0
- package/runtime/scripts/amalgm-mcp/tests/shared-tunnel-rehydration.test.js +0 -84
- package/runtime/scripts/amalgm-mcp/tests/state-docs.test.js +13 -376
- package/runtime/scripts/amalgm-mcp/tests/state-mutations.test.js +0 -309
- package/runtime/scripts/amalgm-mcp/tests/state-shared-replica.test.js +30 -758
- package/runtime/scripts/amalgm-mcp/tests/workspace-cards-store.test.js +3 -72
- package/runtime/scripts/amalgm-mcp/tests/workspace-cards.test.js +1 -89
- package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint-reducer.test.js +24 -55
- package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint.test.js +141 -424
- package/runtime/scripts/amalgm-mcp/tests/workspace-object-tunnel.test.js +3 -171
- package/runtime/scripts/amalgm-mcp/tests/workspace-objects.test.js +7 -220
- package/runtime/scripts/amalgm-mcp/tests/workspace-publication-invariants.test.js +236 -179
- package/runtime/scripts/amalgm-mcp/tests/workspace-reducer.test.js +326 -2228
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-cloud.test.js +3 -5319
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-core.test.js +1 -191
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-store.test.js +17 -3140
- package/runtime/scripts/amalgm-mcp/tests/workspace-wall.test.js +740 -137
- package/runtime/scripts/amalgm-mcp/workspace/access-store.js +1 -5
- package/runtime/scripts/amalgm-mcp/workspace/card.js +11 -35
- package/runtime/scripts/amalgm-mcp/workspace/cards.js +14 -39
- package/runtime/scripts/amalgm-mcp/workspace/checkpoint.js +147 -587
- package/runtime/scripts/amalgm-mcp/workspace/git.js +34 -406
- package/runtime/scripts/amalgm-mcp/workspace/merge.js +181 -102
- package/runtime/scripts/amalgm-mcp/workspace/objects.js +56 -221
- package/runtime/scripts/amalgm-mcp/workspace/reducer.js +538 -1964
- package/runtime/scripts/amalgm-mcp/workspace/rest.js +28 -49
- package/runtime/scripts/amalgm-mcp/workspace/store.js +4 -77
- package/runtime/scripts/amalgm-mcp/workspace/transition.js +192 -1734
- package/runtime/scripts/amalgm-mcp/workspace/tree/inclusion.js +1 -7
- package/runtime/scripts/amalgm-mcp/workspace/tree/local-state.js +61 -73
- package/runtime/scripts/amalgm-mcp/workspace/tree/reducer.js +6 -51
- package/runtime/scripts/amalgm-mcp/workspace/tree/snapshot.js +8 -79
- package/runtime/scripts/amalgm-mcp/workspace/tree-cloud.js +146 -3461
- package/runtime/scripts/amalgm-mcp/workspace/tree-store.js +71 -899
- package/runtime/scripts/amalgm-mcp/workspace/wall.js +538 -370
- package/runtime/scripts/local-gateway.js +1 -0
- package/runtime/scripts/amalgm-mcp/state/doc-disk.js +0 -550
- package/runtime/scripts/amalgm-mcp/tests/code-project-stream.test.js +0 -399
- package/runtime/scripts/amalgm-mcp/tests/fixtures/code-project-stream-v2.json +0 -1
- package/runtime/scripts/amalgm-mcp/tests/workspace-durable.test.js +0 -24
- package/runtime/scripts/amalgm-mcp/tests/workspace-local-intent.test.js +0 -1999
- package/runtime/scripts/amalgm-mcp/tests/workspace-native-file-transaction.test.js +0 -364
- package/runtime/scripts/amalgm-mcp/tests/workspace-provenance.test.js +0 -185
- package/runtime/scripts/amalgm-mcp/tests/workspace-reducer-liveness.test.js +0 -26
- package/runtime/scripts/amalgm-mcp/tests/workspace-sync-stats.test.js +0 -119
- package/runtime/scripts/amalgm-mcp/tests/workspace-transition.test.js +0 -1446
- package/runtime/scripts/amalgm-mcp/workspace/content.js +0 -32
- package/runtime/scripts/amalgm-mcp/workspace/durable.js +0 -45
- package/runtime/scripts/amalgm-mcp/workspace/intent.js +0 -535
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/BUILD.md +0 -31
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/darwin-arm64/amalgm-file-transaction +0 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/linux-x64/amalgm-file-transaction +0 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/build.mjs +0 -72
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/client.js +0 -165
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.mod +0 -5
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.sum +0 -2
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/main.go +0 -2201
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/manifest.json +0 -19
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_darwin.go +0 -18
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_linux.go +0 -18
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_darwin.go +0 -33
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_linux.go +0 -47
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/verify.mjs +0 -43
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_darwin.go +0 -114
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_linux.go +0 -84
- package/runtime/scripts/amalgm-mcp/workspace/project-stream.js +0 -771
- package/runtime/scripts/amalgm-mcp/workspace/provenance.js +0 -240
- package/runtime/scripts/amalgm-mcp/workspace/sync-stats.js +0 -240
- package/runtime/scripts/amalgm-mcp/workspace/tree/floor.js +0 -100
- package/runtime/scripts/amalgm-mcp/workspace/tree/observation-holds.js +0 -127
- package/runtime/scripts/amalgm-mcp/workspace/tree/path-state.js +0 -12
- package/runtime/scripts/amalgm-mcp/workspace/tree/root-binding.js +0 -125
- package/runtime/scripts/amalgm-mcp/workspace/tree/symlinks.js +0 -76
- package/runtime/scripts/amalgm-mcp/workspace/tree-materialization.js +0 -3766
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A pathname has no final entry when either that entry is missing or an
|
|
5
|
-
* ancestor stopped being a directory. Recovery must classify both as
|
|
6
|
-
* absence; the latter is not an I/O failure and must never wedge a WAL.
|
|
7
|
-
*/
|
|
8
|
-
function isPathAbsentError(error) {
|
|
9
|
-
return error?.code === 'ENOENT' || error?.code === 'ENOTDIR';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
module.exports = { isPathAbsentError };
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { isPathAbsentError } = require('./path-state');
|
|
6
|
-
|
|
7
|
-
const ROOT_HOLD_REASONS = new Set([
|
|
8
|
-
'workspace-root-missing',
|
|
9
|
-
'workspace-root-replaced',
|
|
10
|
-
'workspace-root-binding-incomplete',
|
|
11
|
-
'workspace-root-enrollment-pending',
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
function physicalDirectory(rootPath) {
|
|
15
|
-
try {
|
|
16
|
-
const stats = fs.lstatSync(rootPath);
|
|
17
|
-
if (!stats.isDirectory() || stats.isSymbolicLink()) return null;
|
|
18
|
-
return {
|
|
19
|
-
kind: 'folder',
|
|
20
|
-
deviceId: String(stats.dev),
|
|
21
|
-
inode: String(stats.ino),
|
|
22
|
-
dev: String(stats.dev),
|
|
23
|
-
ino: String(stats.ino),
|
|
24
|
-
};
|
|
25
|
-
} catch (error) {
|
|
26
|
-
if (isPathAbsentError(error)) return null;
|
|
27
|
-
throw error;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function inspectWorkspaceRoot(workspace, database) {
|
|
32
|
-
const rootPath = path.resolve(workspace?.path || '');
|
|
33
|
-
const row = workspace?.id
|
|
34
|
-
? database.prepare(`
|
|
35
|
-
SELECT device_id, inode
|
|
36
|
-
FROM workspace_nodes
|
|
37
|
-
WHERE workspace_id = ? AND id = ?
|
|
38
|
-
`).get(workspace.id, workspace.id)
|
|
39
|
-
: null;
|
|
40
|
-
const expectedDeviceId = row?.device_id == null ? null : String(row.device_id);
|
|
41
|
-
const expectedInode = row?.inode == null ? null : String(row.inode);
|
|
42
|
-
const actual = physicalDirectory(rootPath);
|
|
43
|
-
|
|
44
|
-
if ((expectedDeviceId == null) !== (expectedInode == null)) {
|
|
45
|
-
return {
|
|
46
|
-
state: 'held',
|
|
47
|
-
reason: 'workspace-root-binding-incomplete',
|
|
48
|
-
workspaceId: workspace.id,
|
|
49
|
-
rootPath,
|
|
50
|
-
expected: { deviceId: expectedDeviceId, inode: expectedInode },
|
|
51
|
-
actual,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
if (expectedDeviceId == null) {
|
|
55
|
-
return {
|
|
56
|
-
state: 'unbound',
|
|
57
|
-
workspaceId: workspace.id,
|
|
58
|
-
rootPath,
|
|
59
|
-
actual,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
if (!actual) {
|
|
63
|
-
return {
|
|
64
|
-
state: 'held',
|
|
65
|
-
reason: fs.existsSync(rootPath)
|
|
66
|
-
? 'workspace-root-replaced'
|
|
67
|
-
: 'workspace-root-missing',
|
|
68
|
-
workspaceId: workspace.id,
|
|
69
|
-
rootPath,
|
|
70
|
-
expected: { deviceId: expectedDeviceId, inode: expectedInode },
|
|
71
|
-
actual: null,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
if (
|
|
75
|
-
actual.deviceId !== expectedDeviceId
|
|
76
|
-
|| actual.inode !== expectedInode
|
|
77
|
-
) {
|
|
78
|
-
return {
|
|
79
|
-
state: 'held',
|
|
80
|
-
reason: 'workspace-root-replaced',
|
|
81
|
-
workspaceId: workspace.id,
|
|
82
|
-
rootPath,
|
|
83
|
-
expected: { deviceId: expectedDeviceId, inode: expectedInode },
|
|
84
|
-
actual,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
state: 'verified',
|
|
89
|
-
workspaceId: workspace.id,
|
|
90
|
-
rootPath,
|
|
91
|
-
identity: actual,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function rootBindingError(proof) {
|
|
96
|
-
const reason = proof?.reason || (
|
|
97
|
-
proof?.state === 'unbound'
|
|
98
|
-
? 'workspace-root-enrollment-pending'
|
|
99
|
-
: 'workspace-root-replaced'
|
|
100
|
-
);
|
|
101
|
-
return Object.assign(
|
|
102
|
-
new Error(`workspace tree root is not verified: ${reason}`),
|
|
103
|
-
{
|
|
104
|
-
code: 'WORKSPACE_TREE_ROOT_UNVERIFIED',
|
|
105
|
-
reason,
|
|
106
|
-
statusCode: 409,
|
|
107
|
-
paths: proof?.rootPath ? [proof.rootPath] : [],
|
|
108
|
-
proof,
|
|
109
|
-
},
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function requireVerifiedWorkspaceRoot(workspace, database) {
|
|
114
|
-
const proof = inspectWorkspaceRoot(workspace, database);
|
|
115
|
-
if (proof.state !== 'verified') throw rootBindingError(proof);
|
|
116
|
-
return proof;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
module.exports = {
|
|
120
|
-
ROOT_HOLD_REASONS,
|
|
121
|
-
inspectWorkspaceRoot,
|
|
122
|
-
physicalDirectory,
|
|
123
|
-
requireVerifiedWorkspaceRoot,
|
|
124
|
-
rootBindingError,
|
|
125
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function invalidSymlink(node, message) {
|
|
4
|
-
throw Object.assign(new Error(message), {
|
|
5
|
-
code: 'WORKSPACE_TREE_SYMLINK_ESCAPE',
|
|
6
|
-
reason: 'symlink-escapes-workspace',
|
|
7
|
-
statusCode: 409,
|
|
8
|
-
nodeId: node?.id || null,
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function portableTargetSegments(target, node) {
|
|
13
|
-
if (
|
|
14
|
-
typeof target !== 'string'
|
|
15
|
-
|| !target
|
|
16
|
-
|| target.includes('\0')
|
|
17
|
-
|| /^[\\/]/.test(target)
|
|
18
|
-
|| /^[A-Za-z]:/.test(target)
|
|
19
|
-
) {
|
|
20
|
-
invalidSymlink(node, 'workspace tree symlink target must be relative');
|
|
21
|
-
}
|
|
22
|
-
return target.split(/[\\/]+/);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function liveNode(node) {
|
|
26
|
-
return Boolean(node && !node.trashedAt && !node.purgedAt);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function logicalParentSegments(nodes, rootId, node) {
|
|
30
|
-
const segments = [];
|
|
31
|
-
const seen = new Set([node.id]);
|
|
32
|
-
let currentId = node.parentId;
|
|
33
|
-
while (currentId && currentId !== rootId) {
|
|
34
|
-
if (seen.has(currentId)) {
|
|
35
|
-
invalidSymlink(node, 'workspace tree symlink ancestry contains a cycle');
|
|
36
|
-
}
|
|
37
|
-
seen.add(currentId);
|
|
38
|
-
const current = nodes.get(currentId);
|
|
39
|
-
if (!current) {
|
|
40
|
-
invalidSymlink(node, 'workspace tree symlink parent is missing');
|
|
41
|
-
}
|
|
42
|
-
segments.push(current.name);
|
|
43
|
-
currentId = current.parentId;
|
|
44
|
-
}
|
|
45
|
-
if (currentId !== rootId) {
|
|
46
|
-
invalidSymlink(node, 'workspace tree symlink is outside its workspace');
|
|
47
|
-
}
|
|
48
|
-
return segments.reverse();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function validateLiveSymlinkTargets(inputNodes, rootId) {
|
|
52
|
-
const nodes = inputNodes instanceof Map
|
|
53
|
-
? inputNodes
|
|
54
|
-
: new Map((inputNodes || []).map((node) => [node.id, node]));
|
|
55
|
-
for (const node of nodes.values()) {
|
|
56
|
-
if (node.kind !== 'symlink' || !liveNode(node)) continue;
|
|
57
|
-
const resolved = logicalParentSegments(nodes, rootId, node);
|
|
58
|
-
for (const segment of portableTargetSegments(node.symlinkTarget, node)) {
|
|
59
|
-
if (!segment || segment === '.') continue;
|
|
60
|
-
if (segment === '..') {
|
|
61
|
-
if (!resolved.length) {
|
|
62
|
-
invalidSymlink(
|
|
63
|
-
node,
|
|
64
|
-
`workspace tree symlink ${node.id} escapes its workspace`,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
resolved.pop();
|
|
68
|
-
} else {
|
|
69
|
-
resolved.push(segment);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return nodes;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
module.exports = { validateLiveSymlinkTargets };
|